diff --git a/components/include/i_details_resolver.h b/components/include/i_details_resolver.h index ecea297..ae3b0aa 100644 --- a/components/include/i_details_resolver.h +++ b/components/include/i_details_resolver.h @@ -30,7 +30,7 @@ public: virtual bool isVersionAboveR8110() = 0; virtual bool isReverseProxy() = 0; virtual bool isCloudStorageEnabled() = 0; - virtual Maybe> parseNginxMetadata() = 0; + virtual Maybe> parseNginxMetadata() = 0; virtual Maybe> readCloudMetadata() = 0; virtual std::map getResolvedDetails() = 0; #if defined(gaia) || defined(smb) diff --git a/components/security_apps/orchestration/details_resolver/details_resolver.cc b/components/security_apps/orchestration/details_resolver/details_resolver.cc index d78ffc7..ece8423 100644 --- a/components/security_apps/orchestration/details_resolver/details_resolver.cc +++ b/components/security_apps/orchestration/details_resolver/details_resolver.cc @@ -46,7 +46,7 @@ public: bool isReverseProxy() override; bool isCloudStorageEnabled() override; Maybe> readCloudMetadata() override; - Maybe> parseNginxMetadata() override; + Maybe> parseNginxMetadata() override; #if defined(gaia) || defined(smb) bool compareCheckpointVersion(int cp_version, std::function compare_operator) const override; #endif // gaia || smb @@ -230,7 +230,7 @@ isNoResponse(const string &cmd) return !res.ok() || res.unpack().empty(); } -Maybe> +Maybe> DetailsResolver::Impl::parseNginxMetadata() { auto output_path = getConfigurationWithDefault( @@ -243,6 +243,11 @@ DetailsResolver::Impl::parseNginxMetadata() "/scripts/cp-nano-makefile-generator.sh -f -o " + output_path; + const string script_fresh_exe_cmd = + getFilesystemPathConfig() + + "/scripts/cp-nano-makefile-generator-fresh.sh save --save-location " + + output_path; + dbgTrace(D_ORCHESTRATOR) << "Details resolver, srcipt exe cmd: " << srcipt_exe_cmd; if (isNoResponse("which nginx") && isNoResponse("which kong")) { return genError("Nginx or Kong isn't installed"); @@ -265,7 +270,7 @@ DetailsResolver::Impl::parseNginxMetadata() return genError("Cannot open the file with nginx metadata, File: " + output_path); } - string line; + string line; while (getline(input_stream, line)) { lines.push_back(line); } @@ -279,7 +284,37 @@ DetailsResolver::Impl::parseNginxMetadata() << " Error: " << exception.what(); } + if (!isNoResponse("which nginx")) { + auto script_output = DetailsResolvingHanlder::getCommandOutput(script_fresh_exe_cmd); + if (!script_output.ok()) { + return genError("Failed to generate nginx fresh metadata, Error: " + script_output.getErr()); + } + + try { + ifstream input_stream(output_path); + if (!input_stream) { + return genError("Cannot open the file with nginx fresh metadata, File: " + output_path); + } + + string line; + while (getline(input_stream, line)) { + if (line.find("NGX_MODULE_SIGNATURE") == 0) { + lines.push_back(line); + } + } + input_stream.close(); + + orchestration_tools->removeFile(output_path); + } catch (const ifstream::failure &exception) { + dbgWarning(D_ORCHESTRATOR) + << "Cannot read the file with required nginx fresh metadata." + << " File: " << output_path + << " Error: " << exception.what(); + } + } + if (lines.size() == 0) return genError("Failed to read nginx metadata file"); + string nginx_signature; string nginx_version; string config_opt; string cc_opt; @@ -294,6 +329,11 @@ DetailsResolver::Impl::parseNginxMetadata() nginx_version = "nginx-" + line.substr(eq_index + 1); continue; } + if (line.find("NGX_MODULE_SIGNATURE") != string::npos) { + auto eq_index = line.find("="); + nginx_signature = line.substr(eq_index + 1); + continue; + } if (line.find("EXTRA_CC_OPT") != string::npos) { auto eq_index = line.find("="); cc_opt = line.substr(eq_index + 1); @@ -303,7 +343,7 @@ DetailsResolver::Impl::parseNginxMetadata() if (line.back() == '\\') line.pop_back(); config_opt += line; } - return make_tuple(config_opt, cc_opt, nginx_version); + return make_tuple(config_opt, cc_opt, nginx_version, nginx_signature); } Maybe> diff --git a/components/security_apps/orchestration/include/mock/mock_details_resolver.h b/components/security_apps/orchestration/include/mock/mock_details_resolver.h index 3c4a153..c6a1dd7 100644 --- a/components/security_apps/orchestration/include/mock/mock_details_resolver.h +++ b/components/security_apps/orchestration/include/mock/mock_details_resolver.h @@ -21,7 +21,7 @@ #include "maybe_res.h" std::ostream & -operator<<(std::ostream &os, const Maybe> &) +operator<<(std::ostream &os, const Maybe> &) { return os; } @@ -48,7 +48,7 @@ public: MOCK_METHOD0(isGwNotVsx, bool()); MOCK_METHOD0(getResolvedDetails, std::map()); MOCK_METHOD0(isVersionAboveR8110, bool()); - MOCK_METHOD0(parseNginxMetadata, Maybe>()); + MOCK_METHOD0(parseNginxMetadata, Maybe>()); MOCK_METHOD0( readCloudMetadata, Maybe>()); }; diff --git a/components/security_apps/orchestration/orchestration_comp.cc b/components/security_apps/orchestration/orchestration_comp.cc index db4729b..6a8b536 100755 --- a/components/security_apps/orchestration/orchestration_comp.cc +++ b/components/security_apps/orchestration/orchestration_comp.cc @@ -1465,12 +1465,14 @@ private: auto nginx_data = i_details_resolver->parseNginxMetadata(); if (nginx_data.ok()) { + string nginx_signature; string nginx_version; string config_opt; string cc_opt; - tie(config_opt, cc_opt, nginx_version) = nginx_data.unpack(); + tie(config_opt, cc_opt, nginx_version, nginx_signature) = nginx_data.unpack(); agent_data_report << make_pair("attachmentVersion", "Legacy") + << make_pair("nginxSignature", nginx_signature) << make_pair("nginxVersion", nginx_version) << make_pair("configureOpt", config_opt) << make_pair("extraCompilerOpt", cc_opt); @@ -1529,7 +1531,6 @@ private: } else { curr_agent_data_report = agent_data_report; curr_agent_data_report.disableReportSending(); - agent_data_report << AgentReportFieldWithLabel("timestamp", i_time->getWalltimeStr()); } } diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc index 5982e63..62e47ed 100644 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc @@ -140,7 +140,7 @@ public: void expectDetailsResolver() { - Maybe> no_nginx(genError("No nginx")); + Maybe> no_nginx(genError("No nginx")); EXPECT_CALL(mock_details_resolver, getPlatform()).WillRepeatedly(Return(string("linux"))); EXPECT_CALL(mock_details_resolver, getArch()).WillRepeatedly(Return(string("x86_64"))); EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillRepeatedly(Return(false)); diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc index c6b1c07..3e83ed3 100755 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc @@ -168,7 +168,7 @@ public: void expectDetailsResolver() { - Maybe> no_nginx(genError("No nginx")); + Maybe> no_nginx(genError("No nginx")); EXPECT_CALL(mock_details_resolver, getPlatform()).WillRepeatedly(Return(string("linux"))); EXPECT_CALL(mock_details_resolver, getArch()).WillRepeatedly(Return(string("x86_64"))); EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillRepeatedly(Return(false)); diff --git a/components/security_apps/orchestration/update_communication/fog_authenticator.cc b/components/security_apps/orchestration/update_communication/fog_authenticator.cc index 6c34d8d..c58c96f 100755 --- a/components/security_apps/orchestration/update_communication/fog_authenticator.cc +++ b/components/security_apps/orchestration/update_communication/fog_authenticator.cc @@ -168,10 +168,12 @@ FogAuthenticator::registerAgent( auto nginx_data = details_resolver->parseNginxMetadata(); if (nginx_data.ok()) { + string nginx_signature; string nginx_version; string config_opt; string cc_opt; - tie(config_opt, cc_opt, nginx_version) = nginx_data.unpack(); + tie(config_opt, cc_opt, nginx_version, nginx_signature) = nginx_data.unpack(); + request << make_pair("nginxSignature", nginx_signature); request << make_pair("nginxVersion", nginx_version); request << make_pair("configureOpt", config_opt); request << make_pair("extraCompilerOpt", cc_opt); diff --git a/components/security_apps/waap/waap_clib/WaapAssetState.cc b/components/security_apps/waap/waap_clib/WaapAssetState.cc index 4689e32..536ca19 100755 --- a/components/security_apps/waap/waap_clib/WaapAssetState.cc +++ b/components/security_apps/waap/waap_clib/WaapAssetState.cc @@ -424,6 +424,8 @@ WaapAssetState::WaapAssetState(std::shared_ptr signatures, std::string unescape(const std::string & s) { std::string text = s; + size_t orig_size = text.size(); + size_t orig_capacity = text.capacity(); dbgTrace(D_WAAP_SAMPLE_PREPROCESS) << "unescape: (0) '" << text << "'"; fixBreakingSpace(text); @@ -433,7 +435,17 @@ WaapAssetState::WaapAssetState(std::shared_ptr signatures, filterUnicode(text); dbgTrace(D_WAAP_SAMPLE_PREPROCESS) << "unescape: (1) '" << text << "'"; + // inplace unescaping must result in a string of the same size or smaller + dbgAssertOpt(text.size() <= orig_size && text.size() <= text.capacity() && text.capacity() <= orig_capacity) + << AlertInfo(AlertTeam::CORE, "WAAP sample processing") + << "unescape: original size=" << orig_size << " capacity=" << orig_capacity + << " new size=" << text.size() << " capacity=" << text.capacity() + << " text='" << text << "'"; + text = filterUTF7(text); + // update orig_size and orig_capacity after string copy + orig_size = text.size(); + orig_capacity = text.capacity(); dbgTrace(D_WAAP_SAMPLE_PREPROCESS) << "unescape: (1) (after filterUTF7) '" << text << "'"; // 2. Replace %xx sequences by their single-character equivalents. @@ -512,6 +524,14 @@ WaapAssetState::WaapAssetState(std::shared_ptr signatures, } dbgTrace(D_WAAP_SAMPLE_PREPROCESS) << "unescape: (12) '" << text << "'"; + + // inplace unescaping must result in a string of the same size or smaller + dbgAssertOpt(text.size() <= orig_size && text.size() <= text.capacity() && text.capacity() <= orig_capacity) + << AlertInfo(AlertTeam::CORE, "WAAP sample processing") + << "unescape: original size=" << orig_size << " capacity=" << orig_capacity + << " new size=" << text.size() << " capacity=" << text.capacity() + << " text='" << text << "'"; + return text; } diff --git a/components/security_apps/waap/waap_clib/Waf2Util.h b/components/security_apps/waap/waap_clib/Waf2Util.h index 5c42b59..d91da07 100755 --- a/components/security_apps/waap/waap_clib/Waf2Util.h +++ b/components/security_apps/waap/waap_clib/Waf2Util.h @@ -227,59 +227,66 @@ inline bool isHexDigit(const char ch) { template _IT escape_backslashes(_IT first, _IT last) { - _IT result = first; + _IT src = first; + _IT dst = first; + _IT mark = first; + enum { STATE_COPY, STATE_ESCAPE, STATE_OCTAL, STATE_HEX } state = STATE_COPY; unsigned char accVal = 0; unsigned char digitsCount = 0; - _IT mark = first; - for (; first != last; ++first) { + for (; src != last && dst < last; ++src) { switch (state) { case STATE_COPY: - if (*first == '\\') { - mark = first; + if (*src == '\\') { + mark = src; state = STATE_ESCAPE; - } - else { - *result++ = *first; + } else { + *dst++ = *src; } break; case STATE_ESCAPE: { - if (*first >= '0' && *first <= '7') { - accVal = *first - '0'; + if (*src >= '0' && *src <= '7') { + accVal = *src - '0'; digitsCount = 1; state = STATE_OCTAL; break; - } else if (*first == 'x') { + } else if (*src == 'x') { accVal = 0; digitsCount = 0; state = STATE_HEX; break; - } - else { - switch (*first) { - case 'a': *result++ = 7; break; // BELL - case 'b': *result++ = 8; break; // BACKSPACE - case 't': *result++ = 9; break; // HORIZONTAL TAB - case 'n': *result++ = 10; break; // LINEFEED - case 'v': *result++ = 11; break; // VERTICAL TAB - case 'f': *result++ = 12; break; // FORMFEED - case 'r': *result++ = 13; break; // CARRIAGE RETURN - case '\\': *result++ = '\\'; break; // upon seeing double backslash - output only one - case '\"': *result++ = '"'; break; // backslash followed by '"' - output only '"' + } else { + switch (*src) { + // Copy a matching character without the backslash before it + case 'a': *dst++ = 7; break; // BELL + case 'b': *dst++ = 8; break; // BACKSPACE + case 'e': *dst++ = 27; break; // ESCAPE + case 't': *dst++ = 9; break; // HORIZONTAL TAB + case 'n': *dst++ = 10; break; // LINEFEED + case 'v': *dst++ = 11; break; // VERTICAL TAB + case 'f': *dst++ = 12; break; // FORMFEED + case 'r': *dst++ = 13; break; // CARRIAGE RETURN + case '\?': *dst++ = '\?'; break; // QUESTION MARK + case '\\': *dst++ = '\\'; break; // upon seeing double backslash - output only one + case '\"': *dst++ = '\"'; break; // DOUBLE QUOTE + case '\'': *dst++ = '\''; break; // SINGLE QUOTE default: // invalid escape sequence - do not replace it (return original characters) // Copy from back-track, not including current character, and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } // Copy current (terminator) character which is not "escape" and return to copy state // If current character is escape - stay is "escape" state - if (*first != '\\') { - *result++ = *mark++; + if (*src != '\\') { + *dst++ = *src; state = STATE_COPY; + } else { + mark = src; } + break; } state = STATE_COPY; @@ -288,28 +295,26 @@ _IT escape_backslashes(_IT first, _IT last) { break; } case STATE_OCTAL: { - if (*first >='0' && *first<='7') { - accVal = (accVal << 3) | (*first - '0'); + if (*src >= '0' && *src <= '7') { + accVal = (accVal << 3) | (*src - '0'); digitsCount++; - // Up to 3 octal digits imposed by C standard, so after 3 digits accumulation stops. if (digitsCount == 3) { - *result++ = accVal; // output character corresponding to collected accumulated value + *dst++ = accVal; // output character corresponding to collected accumulated value digitsCount = 0; state = STATE_COPY; } - } - else { + } else { // invalid octal digit stops the accumulation - *result++ = accVal; // output character corresponding to collected accumulated value + *dst++ = accVal; // output character corresponding to collected accumulated value digitsCount = 0; - if (*first != '\\') { + if (*src != '\\') { // If terminating character is not backslash output the terminating character - *result++ = *first; + *dst++ = *src; state = STATE_COPY; - } - else { + } else { // If terminating character is backslash start next escape sequence + mark = src; state = STATE_ESCAPE; } } @@ -317,36 +322,33 @@ _IT escape_backslashes(_IT first, _IT last) { break; } case STATE_HEX: { - if (!isHexDigit(*first)) { - // Copy from back-track, not including current character (which is absent), and continue - while (mark < first) { - *result++ = *mark++; + if (!isHexDigit(*src)) { + // Copy from back-track, not including *src character (which is absent), and continue + while (dst <= mark && mark < src) { + *dst++ = *mark++; } - if (*first != '\\') { + if (*src != '\\') { // If terminating character is not backslash output the terminating character - *result++ = *first; + *dst++ = *src; state = STATE_COPY; - } - else { + } else { // If terminating character is backslash start next escape sequence + mark = src; state = STATE_ESCAPE; } - } - else { + } else { accVal = accVal << 4; - if (isdigit(*first)) { - accVal += *first - '0'; - } - else if (*first >= 'a' && *first <= 'f') { - accVal += *first - 'a' + 10; - } - else if (*first >= 'A' && *first <= 'F') { - accVal += *first - 'A' + 10; + if (isdigit(*src)) { + accVal += *src - '0'; + } else if (*src >= 'a' && *src <= 'f') { + accVal += *src - 'a' + 10; + } else if (*src >= 'A' && *src <= 'F') { + accVal += *src - 'A' + 10; } digitsCount++; // exactly 2 hex digits are anticipated, so after 2 digits accumulation stops. if (digitsCount == 2) { - *result++ = accVal; // output character corresponding to collected accumulated value + *dst++ = accVal; // output character corresponding to collected accumulated value digitsCount = 0; state = STATE_COPY; } @@ -356,34 +358,36 @@ _IT escape_backslashes(_IT first, _IT last) { } } - // Handle state at end of input - bool copyBackTrack = true; - switch (state) { - case STATE_HEX: - // this can only happen on this sequence '\xH' where H is a single hex digit. - // in this case the sequence is considered invalid and should be copied verbatim (copyBackTrack=true) - break; - case STATE_OCTAL: - // this can only happen when less than 3 octal digits are found at the value end, like '\1' or '\12' - *result++ = accVal; // output character corresponding to collected accumulated value - copyBackTrack = false; - break; - case STATE_COPY: - copyBackTrack = false; - break; - case STATE_ESCAPE: - break; - } + if (dst < last) { + // Handle state at end of input + bool copyBackTrack = true; + switch (state) { + case STATE_HEX: + // this can only happen on this sequence '\xH' where H is a single hex digit. + // in this case the sequence is considered invalid and should be copied verbatim (copyBackTrack=true) + break; + case STATE_OCTAL: + // this can only happen when less than 3 octal digits are found at the value end, like '\1' or '\12' + *dst++ = accVal; // output character corresponding to collected accumulated value + copyBackTrack = false; + break; + case STATE_COPY: + copyBackTrack = false; + break; + case STATE_ESCAPE: + break; + } - if (copyBackTrack) { - // invalid escape sequence - do not replace it (return original characters) - // Copy from back-track - while (mark < first) { - *result++ = *mark++; + if (copyBackTrack) { + // invalid escape sequence - do not replace it (return original characters) + // Copy from back-track + while (dst <= mark && mark < src) { + *dst++ = *mark++; + } } } - return result; + return dst; } inline bool str_contains(const std::string &haystack, const std::string &needle) @@ -401,7 +405,8 @@ extern const size_t g_htmlEntitiesCount; template _IT escape_html(_IT first, _IT last) { - _IT result = first; + _IT dst = first; + _IT src = first; enum { STATE_COPY, STATE_ESCAPE, @@ -414,26 +419,26 @@ _IT escape_html(_IT first, _IT last) { std::list potentialMatchIndices; size_t matchLength = 0; size_t lastKnownMatchIndex = -1; - _IT mark = first; + _IT mark = src; - for (; first != last; ++first) { + for (; src != last && dst < last; ++src) { switch (state) { case STATE_COPY: - if (*first == '&') { - mark = first; + if (*src == '&') { + mark = src; state = STATE_ESCAPE; } else { - *result++ = *first; + *dst++ = *src; } break; case STATE_ESCAPE: - if (isalpha(*first)) { + if (isalpha(*src)) { // initialize potential matches list potentialMatchIndices.clear(); for (size_t index = 0; index < g_htmlEntitiesCount; ++index) { - if (*first == g_htmlEntities[index].name[0]) { + if (*src == g_htmlEntities[index].name[0]) { potentialMatchIndices.push_back(index); lastKnownMatchIndex = index; } @@ -441,8 +446,8 @@ _IT escape_html(_IT first, _IT last) { // No potential matches - send ampersand and current character to output if (potentialMatchIndices.size() == 0) { - *result++ = '&'; - *result++ = *first; + *dst++ = '&'; + *dst++ = *src; state = STATE_COPY; break; } @@ -451,7 +456,7 @@ _IT escape_html(_IT first, _IT last) { matchLength = 1; state = STATE_NAMED_CHARACTER_REFERENCE; } - else if (*first == '#') { + else if (*src == '#') { digitsSeen = 0; accVal = 0; state = STATE_NUMERIC_START; @@ -459,8 +464,8 @@ _IT escape_html(_IT first, _IT last) { else { // not isalpha and not '#' - this is invalid character reference - do not replace it // (return original characters) - *result++ = '&'; - *result++ = *first; + *dst++ = '&'; + *dst++ = *src; state = STATE_COPY; } break; @@ -479,7 +484,7 @@ _IT escape_html(_IT first, _IT last) { // If there are no more characters in the potntial match name, // or the next tested character doesn't match - kill the match - if ((matchName[matchLength] == '\0') || (matchName[matchLength] != *first)) { + if ((matchName[matchLength] == '\0') || (matchName[matchLength] != *src)) { // remove current element from the list of potential matches pPotentialMatchIndex = potentialMatchIndices.erase(pPotentialMatchIndex); } @@ -495,15 +500,15 @@ _IT escape_html(_IT first, _IT last) { // No more potential matches: unsuccesful match -> flush all consumed characters back to output stream if (potentialMatchIndices.size() == 0) { // Send consumed ampersand to the output - *result++ = '&'; + *dst++ = '&'; // Send those matched characters (these are the same that we consumed) - to the output for (size_t i = 0; i < matchLength; i++) { - *result++ = g_htmlEntities[lastKnownMatchIndex].name[i]; + *dst++ = g_htmlEntities[lastKnownMatchIndex].name[i]; } // Send the character that terminated our search for possible matches - *result++ = *first; + *dst++ = *src; // Continue copying text verbatim state = STATE_COPY; @@ -511,23 +516,23 @@ _IT escape_html(_IT first, _IT last) { } // There are still potential matches and ';' is hit - if (*first == ';') { + if (*src == ';') { // longest match found for the named character reference. // translate it into output character(s) and we're done. unsigned short value = g_htmlEntities[lastKnownMatchIndex].value; // Encode UTF code point as UTF-8 bytes if (value < 0x80) { - *result++ = value; + *dst++ = value; } else if (value < 0x800 ) { - *result++ = (value >> 6) | 0xC0; - *result++ = (value & 0x3F) | 0x80; + *dst++ = (value >> 6) | 0xC0; + *dst++ = (value & 0x3F) | 0x80; } else { // (value <= 0xFFFF : always true because value type is unsigned short which is 16-bit - *result++ = (value >> 12) | 0xE0; - *result++ = ((value >> 6) & 0x3F) | 0x80; - *result++ = (value & 0x3F) | 0x80; + *dst++ = (value >> 12) | 0xE0; + *dst++ = ((value >> 6) & 0x3F) | 0x80; + *dst++ = (value & 0x3F) | 0x80; } // Continue copying text verbatim @@ -538,178 +543,179 @@ _IT escape_html(_IT first, _IT last) { case STATE_NUMERIC_START: digitsSeen = false; accVal = 0; - if (*first == 'x' || *first == 'X') { + if (*src == 'x' || *src == 'X') { state = STATE_HEX; } - else if (isdigit(*first)) { + else if (isdigit(*src)) { digitsSeen = true; - accVal = *first - '0'; + accVal = *src - '0'; state = STATE_NUMERIC; } else { // Sequence started with these two characters: '&#', and here is the third, non-digit character // Copy from back-track, not including current character, and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } - if (*first == '&') { + if (*src == '&') { // Terminator is also start of next escape sequence - mark = first; + mark = src; state = STATE_ESCAPE; break; } else { // Copy the terminating character too - *result++ = *first; + *dst++ = *src; } state = STATE_COPY; } break; case STATE_NUMERIC: - if (!isdigit(*first)) { + if (!isdigit(*src)) { if (digitsSeen) { // Encode UTF code point as UTF-8 bytes if (accVal < 0x80) { - *result++ = accVal; + *dst++ = accVal; } else if (accVal < 0x800 ) { - *result++ = (accVal >> 6) | 0xC0; - *result++ = (accVal & 0x3F) | 0x80; + *dst++ = (accVal >> 6) | 0xC0; + *dst++ = (accVal & 0x3F) | 0x80; } else { // (accVal <= 0xFFFF : always true because accVal type is unsigned short which is 16-bit - *result++ = (accVal >> 12) | 0xE0; - *result++ = ((accVal >> 6) & 0x3F) | 0x80; - *result++ = (accVal & 0x3F) | 0x80; + *dst++ = (accVal >> 12) | 0xE0; + *dst++ = ((accVal >> 6) & 0x3F) | 0x80; + *dst++ = (accVal & 0x3F) | 0x80; } } else { // Copy from back-track, not including current character (which is absent), and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } } - if (*first == '&') { + if (*src == '&') { // Terminator is also start of next escape sequence - mark = first; + mark = src; state = STATE_ESCAPE; break; } - else if (!digitsSeen || *first != ';') { + else if (!digitsSeen || *src != ';') { // Do not copy the ';' but do copy any other terminator // Note: the ';' should remain in the output if there were no digits seen. - *result++ = *first; + *dst++ = *src; } state = STATE_COPY; } else { digitsSeen = true; - accVal = accVal * 10 + *first - '0'; // TODO:: beware of integer overflow? + accVal = accVal * 10 + *src - '0'; // TODO:: beware of integer overflow? } break; case STATE_HEX: - if (!isHexDigit(*first)) { + if (!isHexDigit(*src)) { if (digitsSeen) { // Encode UTF code point as UTF-8 bytes if (accVal < 0x80) { - *result++ = accVal; + *dst++ = accVal; } else if (accVal < 0x800 ) { - *result++ = (accVal >> 6) | 0xC0; - *result++ = (accVal & 0x3F) | 0x80; + *dst++ = (accVal >> 6) | 0xC0; + *dst++ = (accVal & 0x3F) | 0x80; } else { // (accVal <= 0xFFFF : always true because accVal type is unsigned short which is 16-bit - *result++ = (accVal >> 12) | 0xE0; - *result++ = ((accVal >> 6) & 0x3F) | 0x80; - *result++ = (accVal & 0x3F) | 0x80; + *dst++ = (accVal >> 12) | 0xE0; + *dst++ = ((accVal >> 6) & 0x3F) | 0x80; + *dst++ = (accVal & 0x3F) | 0x80; } } else { // Copy from back-track, not including current character (which is absent), and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } } - if (*first == '&') { + if (*src == '&') { // Terminator is also start of next escape sequence - mark = first; + mark = src; state = STATE_ESCAPE; break; } - else if (!digitsSeen || *first != ';') { + else if (!digitsSeen || *src != ';') { // Do not copy the ';' but do copy any other terminator // Note: the ';' should remain in the output if there were no digits seen. - *result++ = *first; + *dst++ = *src; } state = STATE_COPY; } else { digitsSeen = true; accVal = accVal << 4; - if (isdigit(*first)) { - accVal += *first - '0'; + if (isdigit(*src)) { + accVal += *src - '0'; } - else if (*first >= 'a' && *first <= 'f') { - accVal += *first - 'a' + 10; + else if (*src >= 'a' && *src <= 'f') { + accVal += *src - 'a' + 10; } - else if (*first >= 'A' && *first <= 'F') { - accVal += *first - 'A' + 10; + else if (*src >= 'A' && *src <= 'F') { + accVal += *src - 'A' + 10; } } break; } } - if (state == STATE_ESCAPE) { - *result++ = '&'; + if (state == STATE_ESCAPE && dst < last) { + *dst++ = '&'; } - else if (state == STATE_NAMED_CHARACTER_REFERENCE && potentialMatchIndices.size() > 0) { + else if (state == STATE_NAMED_CHARACTER_REFERENCE && potentialMatchIndices.size() > 0 && dst < last) { // Send consumed ampersand to the output - *result++ = '&'; + *dst++ = '&'; // Send those matched characters (these are the same that we consumed) - to the output - for (size_t i = 0; i < matchLength; i++) { + for (size_t i = 0; i < matchLength && dst < last; i++) { // Even if there are multiple potential matches, all of them start with the same // matchLength characters that we consumed! - *result++ = g_htmlEntities[lastKnownMatchIndex].name[i]; + *dst++ = g_htmlEntities[lastKnownMatchIndex].name[i]; } } if (state == STATE_HEX && !digitsSeen) { // Special case of "&#x" // Copy from back-track, not including current character (which is absent), and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } state = STATE_COPY; } else if (state == STATE_HEX || state == STATE_NUMERIC || state == STATE_NUMERIC_START) { - if (digitsSeen) { + if (digitsSeen && dst < last) { // Encode UTF code point as UTF-8 bytes if (accVal < 0x80) { - *result++ = accVal; + *dst++ = accVal; } - else if (accVal < 0x800 ) { - *result++ = (accVal >> 6) | 0xC0; - *result++ = (accVal & 0x3F) | 0x80; + else if (accVal < 0x800 && std::distance(dst, last) >= 2) { + *dst++ = (accVal >> 6) | 0xC0; + *dst++ = (accVal & 0x3F) | 0x80; } - else { // (accVal <= 0xFFFF : always true because accVal type is unsigned short which is 16-bit - *result++ = (accVal >> 12) | 0xE0; - *result++ = ((accVal >> 6) & 0x3F) | 0x80; - *result++ = (accVal & 0x3F) | 0x80; + // (accVal <= 0xFFFF : always true because accVal type is unsigned short which is 16-bit + else if (std::distance(dst, last) >= 3) { + *dst++ = (accVal >> 12) | 0xE0; + *dst++ = ((accVal >> 6) & 0x3F) | 0x80; + *dst++ = (accVal & 0x3F) | 0x80; } } else { // Copy from back-track, not including current character (which is absent), and continue - while (mark < first) { - *result++ = *mark++; + while (dst <= mark && mark < src) { + *dst++ = *mark++; } state = STATE_COPY; } } - return result; + return dst; } // Compare two buffers, case insensitive. Return true if they are equal (case-insensitive) diff --git a/components/signal_handler/signal_handler.cc b/components/signal_handler/signal_handler.cc index 991c2b7..37e8792 100755 --- a/components/signal_handler/signal_handler.cc +++ b/components/signal_handler/signal_handler.cc @@ -43,6 +43,7 @@ #include "agent_core_utilities.h" #define stack_trace_max_len 64 +#define STACK_SIZE (1024 * 1024) // 1 MB stack size using namespace std; using namespace ReportIS; @@ -57,6 +58,12 @@ public: { if (out_trace_file_fd != -1) close(out_trace_file_fd); out_trace_file_fd = -1; + + if (alt_stack.ss_sp != nullptr) { + free(alt_stack.ss_sp); + alt_stack.ss_sp = nullptr; + alt_stack_initialized = false; + } } void @@ -69,6 +76,7 @@ public: void init() { + alt_stack.ss_sp = nullptr; addSignalHandlerRoutine(); addReloadConfigurationRoutine(); } @@ -244,6 +252,28 @@ private: setHandlerPerSignalNum(); } + bool + setupAlternateSignalStack() + { + if (alt_stack_initialized) return true; + alt_stack.ss_sp = malloc(STACK_SIZE); + if (alt_stack.ss_sp == nullptr) { + dbgWarning(D_SIGNAL_HANDLER) << "Failed to allocate alternate stack"; + return false; + } + alt_stack.ss_size = STACK_SIZE; + alt_stack.ss_flags = 0; + + if (sigaltstack(&alt_stack, nullptr) == -1) { + dbgWarning(D_SIGNAL_HANDLER) << "Failed to set up alternate stack"; + free(alt_stack.ss_sp); + return false; + } + dbgInfo(D_SIGNAL_HANDLER) << "Alternate stack allocated successfully. Allocated size: " << STACK_SIZE; + alt_stack_initialized = true; + return true; + } + void setHandlerPerSignalNum() { @@ -261,8 +291,29 @@ private: SIGUSR2 }; + if (!setupAlternateSignalStack()) { + dbgWarning(D_SIGNAL_HANDLER) << "Failed to set up alternate signal stack"; + for (int sig : signals) { + signal(sig, signalHandlerCB); + } + return; + } + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = signalActionHandlerCB; + + sigemptyset(&sa.sa_mask); + for (int sig : signals) { - signal(sig, signalHandlerCB); + if (sig == SIGKILL || sig == SIGSTOP) { + signal(sig, signalHandlerCB); + continue; + } + if (sigaction(sig, &sa, nullptr) == -1) { + dbgError(D_SIGNAL_HANDLER) << "Failed to set signal handler for signal " << sig; + } } } @@ -284,55 +335,30 @@ private: static void signalHandlerCB(int _signal) { - const char *signal_name = ""; + const char *signal_name = strsignal(_signal); char signal_num[3]; + snprintf(signal_num, sizeof(signal_num), "%d", _signal); + + if (out_trace_file_fd == -1) exit(_signal); reset_signal_handler = true; switch(_signal) { - case SIGABRT: { - signal_name = "SIGABRT"; - fini_signal_flag = true; - return; - } - case SIGKILL: { - signal_name = "SIGKILL"; - fini_signal_flag = true; - return; - } - case SIGQUIT: { - signal_name = "SIGQUIT"; - fini_signal_flag = true; - return; - } - case SIGINT: { - signal_name = "SIGINT"; - fini_signal_flag = true; - return; - } + case SIGABRT: + case SIGKILL: + case SIGQUIT: + case SIGINT: case SIGTERM: { - signal_name = "SIGTERM"; fini_signal_flag = true; return; } - case SIGSEGV: { - signal_name = "SIGSEGV"; - break; - } - case SIGBUS: { - signal_name = "SIGBUS"; - break; - } - case SIGILL: { - signal_name = "SIGILL"; - break; - } + case SIGSEGV: + case SIGBUS: + case SIGILL: case SIGFPE: { - signal_name = "SIGFPE"; break; } case SIGPIPE: { - signal_name = "SIGPIPE"; return; } case SIGUSR2: { @@ -341,13 +367,6 @@ private: } } - if (out_trace_file_fd == -1) exit(_signal); - - for (uint i = 0; i < sizeof(signal_num); ++i) { - uint placement = sizeof(signal_num) - 1 - i; - signal_num[placement] = _signal%10 + '0'; - _signal /= 10; - } const char *signal_error_prefix = "Caught signal "; writeData(signal_error_prefix, strlen(signal_error_prefix)); writeData(signal_num, sizeof(signal_num)); @@ -367,6 +386,12 @@ private: exit(_signal); } + static void + signalActionHandlerCB(int signum, siginfo_t *, void *) + { + signalHandlerCB(signum); + } + static void printStackTrace() { @@ -391,16 +416,22 @@ private: for (uint i = 0 ; i < stack_trace_max_len ; i++) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); - - if (unw_get_proc_name(&cursor, name, sizeof(name), &off) == 0) { + int procNameRc = unw_get_proc_name(&cursor, name, sizeof(name), &off); + if (procNameRc == 0 || procNameRc == -UNW_ENOMEM) { const char *open_braces = "<"; writeData(open_braces, strlen(open_braces)); - writeData(name, strlen(name)); + writeData(name, strnlen(name, sizeof(name))); + if (procNameRc != 0) { + const char *dots = "..."; + writeData(dots, strlen(dots)); + } const char *close_braces = ">\n"; writeData(close_braces, strlen(close_braces)); + } else { + const char *error = " -- error: unable to obtain symbol name for this frame\n"; + writeData(error, strlen(error)); } - if (unw_step(&cursor) <= 0) return; } @@ -444,12 +475,16 @@ private: static bool reload_settings_flag; static bool reset_signal_handler; static int out_trace_file_fd; + static stack_t alt_stack; + static bool alt_stack_initialized; }; string SignalHandler::Impl::trace_file_path; bool SignalHandler::Impl::reload_settings_flag = false; bool SignalHandler::Impl::reset_signal_handler = false; int SignalHandler::Impl::out_trace_file_fd = -1; +stack_t SignalHandler::Impl::alt_stack; +bool SignalHandler::Impl::alt_stack_initialized = false; SignalHandler::SignalHandler() : Component("SignalHandler"), pimpl(make_unique()) {} SignalHandler::~SignalHandler() {} diff --git a/core/agent_details/agent_details.cc b/core/agent_details/agent_details.cc index 49b51f8..69dd219 100644 --- a/core/agent_details/agent_details.cc +++ b/core/agent_details/agent_details.cc @@ -276,6 +276,7 @@ void AgentDetails::preload() { registerExpectedConfiguration("orchestration", "Agent details path"); + registerExpectedConfiguration("Agent details", "File path"); registerConfigLoadCb([this] () { readAgentDetails(); }); } diff --git a/core/agent_details_reporter/agent_details_reporter.cc b/core/agent_details_reporter/agent_details_reporter.cc index f954c5d..fe5b110 100644 --- a/core/agent_details_reporter/agent_details_reporter.cc +++ b/core/agent_details_reporter/agent_details_reporter.cc @@ -68,6 +68,7 @@ public: const Maybe &agent_version ) override; + pair generateTimeStamp(); bool addAttr(const string &key, const string &val, bool allow_override = false) override; bool addAttr(const map &attr, bool allow_override = false) override; void deleteAttr(const string &key) override; @@ -218,6 +219,13 @@ AgentDetailsReporter::Impl::isPersistantAttr(const std::string &key) return persistant_attributes.count(key) > 0; } +pair +AgentDetailsReporter::Impl::generateTimeStamp() +{ + auto time_stamp = Singleton::Consume::by()->getWalltimeStr(); + return make_pair("timestamp", time_stamp); +} + bool AgentDetailsReporter::Impl::sendAttributes() { @@ -232,11 +240,10 @@ AgentDetailsReporter::Impl::sendAttributes() attributes[new_attr.first] = new_attr.second; } - AttributesSender attr_to_send(attributes); if (is_server) { AttrSerializer(attributes, "save"); - + attr_to_send.attributes.get().insert(generateTimeStamp()); messaging->sendAsyncMessage(HTTPMethod::PATCH, "/agents", attr_to_send); dbgDebug(D_AGENT_DETAILS) << "Triggered persistent message request with attributes to the Fog"; new_attributes.clear(); @@ -322,6 +329,36 @@ public: attributes = attr; } + void + addAttr(const string &key, const string &val, bool allow_override = false) + { + dbgDebug(D_AGENT_DETAILS) + << "Trying to add new attribute. Key: " + << key + << ", Value: " + << val + << " Should allow override: " + << (allow_override ? "true" : "false"); + auto &attr = attributes.get(); + if (!allow_override) { + if (attr.count(key) > 0) { + dbgWarning(D_AGENT_DETAILS) + << "Cannot override an existing value with a new one. Existing Value: " + << (attr.count(key) > 0 ? attr[key] : ""); + return; + } + } + + attr[key] = val; + if (!attributes.isActive()) attributes.setActive(true); + } + + void + addAttr(const pair &attr, bool allow_override = false) + { + addAttr(attr.first, attr.second, allow_override); + } + private: C2S_PARAM(metaDataReport, additionalMetaData); C2S_OPTIONAL_PARAM(string, agentVersion); @@ -402,6 +439,7 @@ AgentDetailsReporter::Impl::sendReport( additional_metadata.setAdditionalAttributes(attributes); } + additional_metadata.addAttr(generateTimeStamp()); messaging->sendAsyncMessage(HTTPMethod::PATCH, "/agents", additional_metadata); } diff --git a/core/agent_details_reporter/agent_details_reporter_ut/agent_details_reporter_ut.cc b/core/agent_details_reporter/agent_details_reporter_ut/agent_details_reporter_ut.cc index 6d4a7f6..05ca82f 100644 --- a/core/agent_details_reporter/agent_details_reporter_ut/agent_details_reporter_ut.cc +++ b/core/agent_details_reporter/agent_details_reporter_ut/agent_details_reporter_ut.cc @@ -8,6 +8,7 @@ #include "mock/mock_messaging.h" #include "mock/mock_mainloop.h" #include "mock/mock_rest_api.h" +#include "mock/mock_time_get.h" #include "environment.h" #include "agent_details_report.h" @@ -73,6 +74,7 @@ public: StrictMock mock_mainloop; StrictMock mock_messaging; StrictMock mock_rest; + StrictMock mock_time_get; I_MainLoop::Routine periodic_report; I_AgentDetailsReporter *report; CPTestTempfile persistence_attr_file; @@ -85,6 +87,7 @@ public: TEST_F(AgentReporterTest, dataReport) { + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); string custom_data = "Linux version 24.00.15F"; EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, @@ -92,26 +95,33 @@ TEST_F(AgentReporterTest, dataReport) "{\n" " \"additionalMetaData\": {\n" " \"custom_data\": \"Linux version 24.00.15F\"\n" - " }" - "\n}", + " },\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" + "}", MessageCategory::GENERIC, _, _ )).Times(1); - AgentDataReport() << AgentReportField(custom_data);; + AgentDataReport() << AgentReportField(custom_data); } TEST_F(AgentReporterTest, labeledDataReport) { string data = "Linux version 24.00.15F"; + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", "{\n" " \"additionalMetaData\": {\n" " \"this_is_custom_label\": \"Linux version 24.00.15F\"\n" - " }" - "\n}", + " },\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" + "}", MessageCategory::GENERIC, _, _ @@ -123,6 +133,7 @@ TEST_F(AgentReporterTest, multiDataReport) { string custom_data = "Linux version 24.00.15F"; string data_to_report = "Agent Version 95.95.95.00A"; + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", @@ -130,8 +141,11 @@ TEST_F(AgentReporterTest, multiDataReport) " \"additionalMetaData\": {\n" " \"custom_data\": \"Linux version 24.00.15F\",\n" " \"this_is_custom_label\": \"Agent Version 95.95.95.00A\"\n" - " }" - "\n}", + " },\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" + "}", MessageCategory::GENERIC, _, _ @@ -146,7 +160,7 @@ TEST_F(AgentReporterTest, multiDataReportWithRegistrationData) { string custom_data = "Linux version 24.00.15F"; string data_to_report = "Agent Version 95.95.95.00A"; - + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", @@ -158,7 +172,10 @@ TEST_F(AgentReporterTest, multiDataReportWithRegistrationData) " \"agentVersion\": \"1.15.9\",\n" " \"policyVersion\": \"ccc\",\n" " \"platform\": \"bbb\",\n" - " \"architecture\": \"aaa\"\n" + " \"architecture\": \"aaa\",\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" "}", MessageCategory::GENERIC, _, @@ -178,11 +195,15 @@ TEST_F(AgentReporterTest, multiDataReportWithRegistrationData) TEST_F(AgentReporterTest, basicAttrTest) { + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", "{\n" - " \"additionalMetaData\": {}\n" + " \"additionalMetaData\": {},\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" "}", MessageCategory::GENERIC, _, @@ -193,6 +214,7 @@ TEST_F(AgentReporterTest, basicAttrTest) AgentDataReport agent_data; } + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", @@ -201,7 +223,8 @@ TEST_F(AgentReporterTest, basicAttrTest) " \"attributes\": {\n" " \"1\": \"2\",\n" " \"a\": \"1\",\n" - " \"c\": \"d\"\n" + " \"c\": \"d\",\n" + " \"timestamp\": \"Best Time ever\"\n" " }\n" "}", MessageCategory::GENERIC, @@ -219,11 +242,15 @@ TEST_F(AgentReporterTest, basicAttrTest) AgentDataReport agent_data; } + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", "{\n" - " \"additionalMetaData\": {}\n" + " \"additionalMetaData\": {},\n" + " \"attributes\": {\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" "}", MessageCategory::GENERIC, _, @@ -242,7 +269,7 @@ TEST_F(AgentReporterTest, advancedAttrTest) EXPECT_TRUE(report->addAttr({{"c", "d"}, {"1", "2"}, {"send", "me"}})); EXPECT_TRUE(report->addAttr("a", "b")); - + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", @@ -251,7 +278,8 @@ TEST_F(AgentReporterTest, advancedAttrTest) " \"1\": \"2\",\n" " \"a\": \"b\",\n" " \"c\": \"d\",\n" - " \"send\": \"me\"\n" + " \"send\": \"me\",\n" + " \"timestamp\": \"Best Time ever\"\n" " }\n" "}", MessageCategory::GENERIC, @@ -268,6 +296,7 @@ TEST_F(AgentReporterTest, advancedAttrTest) EXPECT_TRUE(report->addAttr("new", "key val")); EXPECT_TRUE(report->addAttr("a", "key val override", true)); + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", @@ -277,7 +306,8 @@ TEST_F(AgentReporterTest, advancedAttrTest) " \"a\": \"key val override\",\n" " \"c\": \"d\",\n" " \"new\": \"key val\",\n" - " \"send\": \"me\"\n" + " \"send\": \"me\",\n" + " \"timestamp\": \"Best Time ever\"\n" " }\n" "}", MessageCategory::GENERIC, @@ -291,6 +321,7 @@ TEST_F(AgentReporterTest, advancedAttrTest) TEST_F(AgentReporterTest, RestDetailsTest) { stringstream rest_call_parameters; + stringstream rest_call_parameters_with_timestamp; rest_call_parameters << "{\n" << " \"attributes\": {\n" @@ -300,17 +331,28 @@ TEST_F(AgentReporterTest, RestDetailsTest) << " \"send\": \"me\"\n" << " }\n" << "}"; + + rest_call_parameters_with_timestamp + << "{\n" + << " \"attributes\": {\n" + << " \"1\": \"2\",\n" + << " \"a\": \"key val override\",\n" + << " \"c\": \"d\",\n" + << " \"send\": \"me\",\n" + << " \"timestamp\": \"Best Time ever\"\n" + << " }\n" + << "}"; add_details_rest_cb->performRestCall(rest_call_parameters); + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", - rest_call_parameters.str(), + rest_call_parameters_with_timestamp.str(), MessageCategory::GENERIC, _, _ )).Times(1); - EXPECT_TRUE(report->sendAttributes()); is_server_mode = false; @@ -365,6 +407,18 @@ TEST_F(AgentReporterTest, PersistenceAttrTest) "}" ); + string expected_attributes_with_timestamp( + "{\n" + " \"attributes\": {\n" + " \"1\": \"2\",\n" + " \"a\": \"key val override\",\n" + " \"c\": \"d\",\n" + " \"send\": \"me\",\n" + " \"timestamp\": \"Best Time ever\"\n" + " }\n" + "}" + ); + write_attributes << expected_attributes; write_attributes.close(); @@ -372,10 +426,11 @@ TEST_F(AgentReporterTest, PersistenceAttrTest) EXPECT_CALL(mock_rest, mockRestCall(RestAction::ADD, "agent-details-attr", _)).WillOnce(Return(true)); agent_details_reporter_comp.init(); + EXPECT_CALL(mock_time_get, getWalltimeStr()).WillOnce(Return("Best Time ever")); EXPECT_CALL(mock_messaging, sendAsyncMessage( HTTPMethod::PATCH, "/agents", - expected_attributes, + expected_attributes_with_timestamp, MessageCategory::GENERIC, _, _ diff --git a/core/include/internal/agent_details_reporter.h b/core/include/internal/agent_details_reporter.h index fec0c05..dbadd7b 100644 --- a/core/include/internal/agent_details_reporter.h +++ b/core/include/internal/agent_details_reporter.h @@ -30,6 +30,7 @@ class AgentDetailsReporter Singleton::Consume, Singleton::Consume, Singleton::Consume, + Singleton::Consume, Singleton::Consume { public: diff --git a/core/include/services_sdk/resources/intelligence_invalidation.h b/core/include/services_sdk/resources/intelligence_invalidation.h index 985c1b4..d56c139 100644 --- a/core/include/services_sdk/resources/intelligence_invalidation.h +++ b/core/include/services_sdk/resources/intelligence_invalidation.h @@ -53,6 +53,51 @@ private: std::map> set_string_attr; }; +class IpAddressRange +{ +public: + IpAddressRange() = default; + IpAddressRange(const std::string &min, const std::string &max) : min(min), max(max) {} + bool operator==(const IpAddressRange &other) const { return min == other.min && max == other.max; } + + const std::string getMin() const { return min; } + const std::string getMax() const { return max; } + + template + void serialize(Archive &ar) { + ar(CEREAL_NVP(max), CEREAL_NVP(min)); + } + +private: + std::string min; + std::string max; +}; + +class IpAttributes +{ +public: + IpAttributes() = default; + IpAttributes & addIpv4Addresses(const std::string &val); + IpAttributes & addIpv6Addresses(const std::string &val); + IpAttributes & addIpv4AddressRanges(const IpAddressRange &val); + IpAttributes & addIpv6AddressRanges(const IpAddressRange &val); + Maybe, void> getIpv4Addresses() const; + Maybe, void> getIpv6Addresses() const; + Maybe, void> getIpv4AddressRanges() const; + Maybe, void> getIpv6AddressRanges() const; + Maybe genObject() const; + bool isEmpty() const; + bool matches(const IpAttributes &other) const; + void serialize(cereal::JSONInputArchive &ar); + void performOutputingSchema(std::ostream &, int); + +private: + std::vector ipv4_addresses; + std::vector ipv6_addresses; + std::vector ipv4_address_ranges; + std::vector ipv6_address_ranges; +}; + class Invalidation { public: @@ -60,14 +105,14 @@ public: Invalidation & setClassifier(ClassifierType type, const std::string &val); Invalidation & addMainAttr(const StrAttributes &attr); - Invalidation & addAttr(const StrAttributes &attr); + Invalidation & addAttr(const IpAttributes &attr); Invalidation & setSourceId(const std::string &id); Invalidation & setObjectType(ObjectType type); Invalidation & setInvalidationType(InvalidationType type); std::string getClassifier(ClassifierType type) const { return classifiers[type]; } std::vector getMainAttributes() const { return main_attributes; } - std::vector getAttributes() const { return attributes; } + std::vector getAttributes() const { return attributes; } const Maybe & getSourceId() const { return source_id; } const Maybe & getObjectType() const { return object_type; } const Maybe & getInvalidationType() const { return invalidation_type; } @@ -86,10 +131,11 @@ public: private: bool attr_matches(const std::vector ¤t, const std::vector &other) const; + bool attr_matches(const std::vector ¤t, const std::vector &other) const; EnumArray classifiers; std::vector main_attributes; - std::vector attributes; + std::vector attributes; Maybe source_id; Maybe object_type; Maybe invalidation_type; diff --git a/core/intelligence_is_v2/intelligence_comp_v2.cc b/core/intelligence_is_v2/intelligence_comp_v2.cc index 7500051..89008eb 100644 --- a/core/intelligence_is_v2/intelligence_comp_v2.cc +++ b/core/intelligence_is_v2/intelligence_comp_v2.cc @@ -254,7 +254,7 @@ private: C2S_OPTIONAL_PARAM(string, sourceId); C2S_OPTIONAL_PARAM(string, invalidationRegistrationId); C2S_OPTIONAL_PARAM(vector, mainAttributes); - C2S_OPTIONAL_PARAM(vector, attributes); + C2S_OPTIONAL_PARAM(vector, attributes); C2S_OPTIONAL_PARAM(string, invalidationType); }; @@ -624,7 +624,7 @@ private: query_request.isBulk() ? queries_uri : query_uri, *json_body, MessageCategory::INTELLIGENCE, - global_req_md + query_request.getReqMD().getHostName().empty() ? global_req_md : query_request.getReqMD() ); if (!req_data.ok()) { auto response_error = req_data.getErr().toString(); diff --git a/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc b/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc index 3895ad1..752c61d 100644 --- a/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc +++ b/core/intelligence_is_v2/intelligence_is_v2_ut/invalidation_ut.cc @@ -32,6 +32,30 @@ TEST(StringAttributesBasic, SettersAndGetters) EXPECT_FALSE(string_attributes.isEmpty()); EXPECT_EQ(string_attributes.getStringAttr("attr1").unpack(), "1"); EXPECT_EQ(string_attributes.getStringSetAttr("attr2").unpack(), vals); + + IpAttributes attributes; + + EXPECT_TRUE(attributes.isEmpty()); + EXPECT_FALSE(attributes.getIpv4Addresses().ok()); + EXPECT_FALSE(attributes.getIpv6Addresses().ok()); + EXPECT_FALSE(attributes.getIpv4AddressRanges().ok()); + EXPECT_FALSE(attributes.getIpv6AddressRanges().ok()); + + IpAddressRange range("1.1.1.1", "1.1.1.5"); + attributes + .addIpv4Addresses("1.1.1.2") + .addIpv4AddressRanges(range) + .addIpv6Addresses("1.1.1.2") + .addIpv6AddressRanges(range); + + + EXPECT_FALSE(attributes.isEmpty()); + vector ip_vector = {"1.1.1.2"}; + vector ip_range_vector = {range}; + EXPECT_EQ(attributes.getIpv4Addresses().unpack(), ip_vector); + EXPECT_EQ(attributes.getIpv4AddressRanges().unpack(), ip_range_vector); + EXPECT_EQ(attributes.getIpv6Addresses().unpack(), ip_vector); + EXPECT_EQ(attributes.getIpv6AddressRanges().unpack(), ip_range_vector); } TEST(StringAttributesBasic, attr_schema) @@ -51,6 +75,39 @@ TEST(StringAttributesBasic, attr_schema) " ]\n" "}"; EXPECT_EQ(ss.str(), expected_schema); + + IpAddressRange range("1.1.1.1", "1.1.1.5"); + IpAttributes attributes = IpAttributes() + .addIpv4Addresses("1.1.1.2") + .addIpv4Addresses("1.1.1.3") + .addIpv4AddressRanges(range) + .addIpv6Addresses("1.1.1.4") + .addIpv6AddressRanges(range); + stringstream attr_ss; + attributes.performOutputingSchema(attr_ss, 0); + expected_schema = + "{\n" + " \"ipv4Addresses\": [\n" + " \"1.1.1.2\",\n" + " \"1.1.1.3\"\n" + " ],\n" + " \"ipv6Addresses\": [\n" + " \"1.1.1.4\"\n" + " ],\n" + " \"ipv4AddressesRange\": [\n" + " {\n" + " \"max\": \"1.1.1.5\",\n" + " \"min\": \"1.1.1.1\"\n" + " }\n" + " ],\n" + " \"ipv6AddressesRange\": [\n" + " {\n" + " \"max\": \"1.1.1.5\",\n" + " \"min\": \"1.1.1.1\"\n" + " }\n" + " ]\n" + "}"; + EXPECT_EQ(attr_ss.str(), expected_schema); } TEST(StringAttributesBasic, Matching) @@ -105,6 +162,20 @@ TEST(StringAttributesBasic, genObject) string expected_json = "{ \"attr1\": \"1\", \"attr2\": [ \"2\", \"3\" ] }"; EXPECT_EQ(string_attributes.genObject().unpack(), expected_json); + + IpAddressRange range("1.1.1.1", "1.1.1.5"); + IpAttributes attributes = IpAttributes() + .addIpv4Addresses("1.1.1.2") + .addIpv4Addresses("1.1.1.3") + .addIpv4AddressRanges(range) + .addIpv6Addresses("1.1.1.4") + .addIpv6AddressRanges(range); + + expected_json = + "{ \"ipv4Addresses\": [ \"1.1.1.2\", \"1.1.1.3\" ], \"ipv6Addresses\": [ \"1.1.1.4\" ], " + "\"ipv4AddressesRange\": [ { \"max\": \"1.1.1.5\", \"min\": \"1.1.1.1\" } ], " + "\"ipv6AddressesRange\": [ { \"max\": \"1.1.1.5\", \"min\": \"1.1.1.1\" } ] }"; + EXPECT_EQ(attributes.genObject().unpack(), expected_json); } TEST(InvalidationBasic, SettersAndGetters) @@ -125,15 +196,15 @@ TEST(InvalidationBasic, SettersAndGetters) EXPECT_FALSE(invalidation.getInvalidationType().ok()); set main_vals = { "2", "3" }; - set vals = { "5", "6" }; + vector vals = {"1.1.1.1", "2.2.2.2"}; auto main_attr = StrAttributes() .addStringAttr("main_attr1", "1") .addStringSetAttr("main_attr2", main_vals); - auto attr = StrAttributes() - .addStringAttr("attr1", "4") - .addStringSetAttr("attr2", vals); + auto attr = IpAttributes() + .addIpv4Addresses("1.1.1.1") + .addIpv4Addresses("2.2.2.2"); invalidation .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -148,8 +219,7 @@ TEST(InvalidationBasic, SettersAndGetters) EXPECT_EQ(invalidation.getClassifier(ClassifierType::FAMILY), "ccc"); EXPECT_EQ(invalidation.getMainAttributes().begin()->getStringAttr("main_attr1").unpack(), "1"); EXPECT_EQ(invalidation.getMainAttributes().begin()->getStringSetAttr("main_attr2").unpack(), main_vals); - EXPECT_EQ(invalidation.getAttributes().begin()->getStringAttr("attr1").unpack(), "4"); - EXPECT_EQ(invalidation.getAttributes().begin()->getStringSetAttr("attr2").unpack(), vals); + EXPECT_EQ(invalidation.getAttributes().begin()->getIpv4Addresses().unpack(), vals); EXPECT_EQ(invalidation.getSourceId().unpack(), "id"); EXPECT_EQ(invalidation.getObjectType().unpack(), Intelligence::ObjectType::ASSET); EXPECT_EQ(invalidation.getInvalidationType().unpack(), InvalidationType::DELETE); @@ -164,9 +234,9 @@ TEST(InvalidationBasic, Matching) .addStringAttr("main_attr1", "1") .addStringSetAttr("main_attr2", main_vals); - auto attr = StrAttributes() - .addStringAttr("attr1", "4") - .addStringSetAttr("attr2", vals); + auto attr = IpAttributes() + .addIpv4Addresses("1.1.1.1") + .addIpv4Addresses("2.2.2.2"); auto base_invalidation = Invalidation("aaa") .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -179,10 +249,9 @@ TEST(InvalidationBasic, Matching) .addStringSetAttr("main_attr2", main_vals) .addStringAttr("main_attr3", "6"); - auto matching_attr = StrAttributes() - .addStringAttr("attr1", "4") - .addStringSetAttr("attr2", vals) - .addStringAttr("attr3", "7"); + auto matching_attr = IpAttributes() + .addIpv4Addresses("1.1.1.1") + .addIpv4Addresses("2.2.2.2"); auto matching_invalidation = Invalidation("aaa") .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -212,10 +281,9 @@ TEST(InvalidationBasic, Matching) EXPECT_FALSE(base_invalidation.matches(missing_attr_invalidation_main)); - auto missing_attr = StrAttributes() - .addStringAttr("attr1", "4") - .addStringAttr("attr2", "2") - .addStringAttr("attr3", "7"); + auto missing_attr = IpAttributes() + .addIpv4Addresses("2.2.2.2") + .addIpv4Addresses("3.3.3.3"); auto missing_attr_invalidation = Invalidation("aaa") .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -280,7 +348,7 @@ public: intelligence.preload(); intelligence.init(); main_attr.addStringAttr("attr2", "2"); - attr.addStringAttr("attr3", "3"); + attr.addIpv4Addresses("1.1.1.1"); } bool @@ -291,7 +359,7 @@ public: } StrAttributes main_attr; - StrAttributes attr; + IpAttributes attr; StrictMock messaging_mock; StrictMock mock_ml; NiceMock mock_time; @@ -350,7 +418,7 @@ TEST_F(IntelligenceInvalidation, sending_public_invalidation) "\"objectType\": \"asset\", " "\"sourceId\": \"id\", " "\"mainAttributes\": [ { \"attr2\": \"2\" } ], " - "\"attributes\": [ { \"attr3\": \"3\" } ]" + "\"attributes\": [ { \"ipv4Addresses\": [ \"1.1.1.1\" ] } ]" " } ] }"; EXPECT_EQ(invalidation_json, expected_json); EXPECT_FALSE(md.getConnectionFlags().isSet(MessageConnectionConfig::UNSECURE_CONN)); @@ -390,7 +458,7 @@ TEST_F(IntelligenceInvalidation, multiple_assets_invalidation) "\"objectType\": \"asset\", " "\"sourceId\": \"id\", " "\"mainAttributes\": [ { \"attr2\": \"2\" }, { \"attr2\": \"22\", \"attr3\": [ \"33\", \"44\" ] } ], " - "\"attributes\": [ { \"attr3\": \"3\" } ]" + "\"attributes\": [ { \"ipv4Addresses\": [ \"1.1.1.1\" ] } ]" " } ] }"; EXPECT_EQ(invalidation_json, expected_json); } @@ -439,7 +507,7 @@ TEST_F(IntelligenceInvalidation, sending_private_invalidation) "\"objectType\": \"asset\", " "\"sourceId\": \"id\", " "\"mainAttributes\": [ { \"attr2\": \"2\" } ], " - "\"attributes\": [ { \"attr3\": \"3\" } ]" + "\"attributes\": [ { \"ipv4Addresses\": [ \"1.1.1.1\" ] } ]" " } ] }"; EXPECT_EQ(invalidation_json, expected_json); EXPECT_TRUE(md.getConnectionFlags().isSet(MessageConnectionConfig::UNSECURE_CONN)); @@ -484,7 +552,7 @@ TEST_F(IntelligenceInvalidation, register_for_invalidation) EXPECT_THAT(body, HasSubstr("\"url\": \"http://127.0.0.1:7000/set-new-invalidation\"")); EXPECT_THAT(body, HasSubstr("\"apiVersion\": \"v2\", \"communicationType\": \"sync\"")); EXPECT_THAT(body, HasSubstr("\"mainAttributes\": [ { \"attr2\": \"2\" } ]")); - EXPECT_THAT(body, HasSubstr("\"attributes\": [ { \"attr3\": \"3\" } ]")); + EXPECT_THAT(body, HasSubstr("\"attributes\": [ { \"ipv4Addresses\": [ \"1.1.1.1\" ] } ]")); EXPECT_TRUE(md.getConnectionFlags().isSet(MessageConnectionConfig::UNSECURE_CONN)); EXPECT_THAT(body, HasSubstr("\"capabilities\": { \"getBulkCallback\": true }")); @@ -888,11 +956,19 @@ TEST_F(IntelligenceInvalidation, invalidation_cb_match_by_registration_id) configuration << "}"; Singleton::Consume::from(conf)->loadConfiguration(configuration); + IpAddressRange range("1.1.1.1", "1.1.1.5"); + IpAttributes attributes = IpAttributes() + .addIpv4Addresses("1.1.1.2") + .addIpv4AddressRanges(range) + .addIpv6Addresses("1.1.1.2") + .addIpv6AddressRanges(range); + auto base_main_attr2 = StrAttributes() .addStringAttr("attr3", "3"); auto invalidation_to_register = Invalidation("aaa") .addMainAttr(main_attr) .addMainAttr(base_main_attr2) + .addAttr(attributes) .setSourceId("id") .setClassifier(ClassifierType::FAMILY, "ccc") .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -911,6 +987,7 @@ TEST_F(IntelligenceInvalidation, invalidation_cb_match_by_registration_id) auto matching_invalidation = Invalidation("aaa") .addMainAttr(matching_second_main_attribute) + .addAttr(attributes) .setSourceId("id") .setClassifier(ClassifierType::FAMILY, "ccc") .setClassifier(ClassifierType::CATEGORY, "bbb") @@ -919,6 +996,7 @@ TEST_F(IntelligenceInvalidation, invalidation_cb_match_by_registration_id) auto invalidation_2_to_register = Invalidation("aaa") .addMainAttr(base_main_attr2) + .addAttr(attributes) .setSourceId("id") .setClassifier(ClassifierType::FAMILY, "ccc") .setClassifier(ClassifierType::CATEGORY, "bbb") diff --git a/core/intelligence_is_v2/invalidation.cc b/core/intelligence_is_v2/invalidation.cc index 21244b4..7281c7c 100644 --- a/core/intelligence_is_v2/invalidation.cc +++ b/core/intelligence_is_v2/invalidation.cc @@ -20,6 +20,8 @@ #include "i_intelligence_is_v2.h" +USE_DEBUG_FLAG(D_INTELLIGENCE); + using namespace Intelligence; using namespace std; @@ -203,6 +205,18 @@ Invalidation::attr_matches(const vector ¤t, const vector ¤t, const vector &other) const +{ + if (current.empty()) return true; + for (const auto &attr : current) { + for(const auto &other_attr : other) { + if (attr.matches(other_attr)) return true; + } + } + return false; +} + bool Invalidation::matches(const Invalidation &other) const { @@ -230,7 +244,7 @@ Invalidation::matches(const Invalidation &other) const } Invalidation & -Invalidation::addAttr(const StrAttributes &attr) +Invalidation::addAttr(const IpAttributes &attr) { attributes.emplace_back(attr); return *this; @@ -378,3 +392,224 @@ StrAttributes::performOutputingSchema(ostream &out, int level) { } RestHelper::printIndent(out, level) << "}"; } + +IpAttributes & +IpAttributes::addIpv4Addresses(const string &val) +{ + ipv4_addresses.push_back(val); + return *this; +} + +IpAttributes & +IpAttributes::addIpv6Addresses(const string &val) +{ + ipv6_addresses.push_back(val); + return *this; +} + +IpAttributes & +IpAttributes::addIpv4AddressRanges(const IpAddressRange &val) +{ + ipv4_address_ranges.push_back(val); + return *this; +} + +IpAttributes & +IpAttributes::addIpv6AddressRanges(const IpAddressRange &val) +{ + ipv6_address_ranges.push_back(val); + return *this; +} + +Maybe, void> +IpAttributes::getIpv4Addresses() const +{ + if (ipv4_addresses.empty()) return genError(); + return ipv4_addresses; +} + +Maybe, void> +IpAttributes::getIpv6Addresses() const +{ + if (ipv6_addresses.empty()) return genError(); + return ipv6_addresses; +} + +Maybe, void> +IpAttributes::getIpv4AddressRanges() const +{ + if (ipv4_address_ranges.empty()) return genError(); + return ipv4_address_ranges; +} + +Maybe, void> +IpAttributes::getIpv6AddressRanges() const +{ + if (ipv6_address_ranges.empty()) return genError(); + return ipv6_address_ranges; +} + +Maybe +IpAttributes::genObject() const +{ + stringstream attributes_ss; + if (this->isEmpty()) return genError(); + bool internal_first = true; + bool first = true; + attributes_ss << "{ "; + if (!ipv4_addresses.empty()) { + attributes_ss << "\"ipv4Addresses\": [ "; + for (auto &attr : ipv4_addresses) { + if (!internal_first) attributes_ss << ", "; + attributes_ss << "\"" << attr << "\""; + internal_first = false; + } + attributes_ss << " ]"; + first = false; + } + + if (!ipv6_addresses.empty()) { + if (!first) attributes_ss << ", "; + attributes_ss << "\"ipv6Addresses\": [ "; + internal_first = true; + for (auto &attr : ipv6_addresses) { + if (!internal_first) attributes_ss << ", "; + attributes_ss << "\"" << attr << "\""; + internal_first = false; + } + attributes_ss << " ]"; + first = false; + } + + if (!ipv4_address_ranges.empty()) { + if (!first) attributes_ss << ", "; + attributes_ss << "\"ipv4AddressesRange\": [ "; + internal_first = true; + for (auto &attr : ipv4_address_ranges) { + if (!internal_first) attributes_ss << ", "; + attributes_ss << "{ \"max\": \"" << attr.getMax() << "\", \"min\": \"" << attr.getMin() << "\" }"; + internal_first = false; + } + attributes_ss << " ]"; + first = false; + } + + if (!ipv6_address_ranges.empty()) { + if (!first) attributes_ss << ", "; + attributes_ss << "\"ipv6AddressesRange\": [ "; + internal_first = true; + for (auto &attr : ipv6_address_ranges) { + if (!internal_first) attributes_ss << ", "; + attributes_ss << "{ \"max\": \"" << attr.getMax() << "\", \"min\": \"" << attr.getMin() << "\" }"; + internal_first = false; + } + attributes_ss << " ]"; + first = false; + } + + attributes_ss << " }"; + return attributes_ss.str(); +} + +bool +IpAttributes::isEmpty() const +{ + return + ipv4_addresses.empty() && + ipv6_addresses.empty() && + ipv4_address_ranges.empty() && + ipv6_address_ranges.empty(); +} + +bool +IpAttributes::matches(const IpAttributes &other) const +{ + return + ipv4_addresses == other.ipv4_addresses && + ipv6_addresses == other.ipv6_addresses && + ipv4_address_ranges == other.ipv4_address_ranges && + ipv6_address_ranges == other.ipv6_address_ranges; +} + +void +IpAttributes::serialize(cereal::JSONInputArchive &ar) +{ + try { + ar(cereal::make_nvp("ipv4Addresses", ipv4_addresses)); + ar(cereal::make_nvp("ipv4AddressesRange", ipv4_address_ranges)); + ar(cereal::make_nvp("ipv6Addresses", ipv6_addresses)); + ar(cereal::make_nvp("ipv6AddressesRange", ipv6_address_ranges)); + } catch (cereal::Exception &e) { + dbgError(D_INTELLIGENCE) << e.what(); + } +} + +void +IpAttributes::performOutputingSchema(ostream &out, int level) +{ + bool first = true; + bool internal_first = true; + RestHelper::printIndent(out, level) << "{\n"; + + if (!ipv4_addresses.empty()) { + RestHelper::printIndent(out, level + 1) << "\"ipv4Addresses\": [\n"; + for (auto &attr : ipv4_addresses) { + if (!internal_first) out << ",\n"; + RestHelper::printIndent(out, level + 2) << "\"" << attr << "\""; + internal_first = false; + } + out << "\n"; + RestHelper::printIndent(out, level + 1) << "]"; + first = false; + } + + if (!ipv6_addresses.empty()) { + if (!first) out << ",\n"; + RestHelper::printIndent(out, level + 1) << "\"ipv6Addresses\": [\n"; + internal_first = true; + for (auto &attr : ipv6_addresses) { + if (!internal_first) out << ",\n"; + RestHelper::printIndent(out, level + 2) << "\"" << attr << "\""; + internal_first = false; + } + out << "\n"; + RestHelper::printIndent(out, level + 1) << "]"; + first = false; + } + + if (!ipv4_address_ranges.empty()) { + if (!first) out << ",\n"; + RestHelper::printIndent(out, level + 1) << "\"ipv4AddressesRange\": [\n"; + internal_first = true; + for (auto &attr : ipv4_address_ranges) { + if (!internal_first) out << ",\n"; + RestHelper::printIndent(out, level + 2) << "{\n"; + RestHelper::printIndent(out, level + 3) << "\"max\": \"" << attr.getMax() << "\",\n"; + RestHelper::printIndent(out, level + 3) << "\"min\": \"" << attr.getMin() << "\"\n"; + RestHelper::printIndent(out, level + 2) << "}"; + internal_first = false; + } + out << "\n"; + RestHelper::printIndent(out, level + 1) << "]"; + first = false; + } + + if (!ipv6_address_ranges.empty()) { + if (!first) out << ",\n"; + RestHelper::printIndent(out, level + 1) << "\"ipv6AddressesRange\": [\n"; + internal_first = true; + for (auto &attr : ipv6_address_ranges) { + if (!internal_first) out << ",\n"; + RestHelper::printIndent(out, level + 2) << "{\n"; + RestHelper::printIndent(out, level + 3) << "\"max\": \"" << attr.getMax() << "\",\n"; + RestHelper::printIndent(out, level + 3) << "\"min\": \"" << attr.getMin() << "\"\n"; + RestHelper::printIndent(out, level + 2) << "}"; + internal_first = false; + } + out << "\n"; + RestHelper::printIndent(out, level + 1) << "]"; + first = false; + } + + RestHelper::printIndent(out, level) << "\n}"; +} diff --git a/core/rest/rest_server.cc b/core/rest/rest_server.cc index 8f99d11..e71438d 100644 --- a/core/rest/rest_server.cc +++ b/core/rest/rest_server.cc @@ -163,10 +163,14 @@ RestServer::Impl::init() } } + bool is_ipv6 = false; if (accept_get_from_external_ip) { + is_ipv6 = true; fd = socket(AF_INET6, SOCK_STREAM, 0); - } else { + } + if (fd == -1) { fd = socket(AF_INET, SOCK_STREAM, 0); + is_ipv6 = false; } dbgAssert(fd >= 0) << alert << "Failed to open a socket"; @@ -175,7 +179,8 @@ RestServer::Impl::init() dbgWarning(D_API) << "Could not set the socket options"; } - if (accept_get_from_external_ip) { + if (is_ipv6) { + dbgDebug(D_API) << "IPv6 socket opened successfully"; int option = 0; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &option, sizeof(option)) < 0) { dbgWarning(D_API) << "Could not set the IPV6_V6ONLY option"; @@ -185,16 +190,24 @@ RestServer::Impl::init() bzero(&addr6, sizeof(addr6)); addr6.sin6_family = AF_INET6; addr6.sin6_addr = in6addr_any; + dbgDebug(D_API) << "Socket listening on any address"; while (!bindRestServerSocket(addr6, port_range)) { mainloop->yield(bind_retry_interval_msec); } listening_port = ntohs(addr6.sin6_port); } else { + dbgDebug(D_API) << "IPv4 socket opened successfully"; struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (accept_get_from_external_ip) { + addr.sin_addr.s_addr = htonl(INADDR_ANY); + dbgDebug(D_API) << "Socket listening on any address"; + } else { + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + dbgDebug(D_API) << "Socket listening on local address"; + } while (!bindRestServerSocket(addr, port_range)) { mainloop->yield(bind_retry_interval_msec); diff --git a/nodes/orchestration/package/orchestration_package.sh b/nodes/orchestration/package/orchestration_package.sh index e276fb4..d87a7bd 100755 --- a/nodes/orchestration/package/orchestration_package.sh +++ b/nodes/orchestration/package/orchestration_package.sh @@ -29,8 +29,10 @@ is_wlp_orchestration="false" ORCHESTRATION_EXE_SOURCE_PATH="./bin/orchestration_comp" NGINX_METADAT_EXTRACTOR_PATH="./scripts/cp-nano-makefile-generator.sh" +NGINX_FRESH_METADATA_EXTRACTOR_PATH="./scripts/cp-nano-makefile-generator-fresh.sh" ORCHESTRATION_FILE_NAME="cp-nano-orchestration" NGINX_METADDATA_EXTRACTOR_NAME="cp-nano-makefile-generator.sh" +NGINX_FRESH_METADATA_EXTRACTOR_NAME="cp-nano-makefile-generator-fresh.sh" GET_CLOUD_METADATA_PATH="get-cloud-metadata.sh" AGENT_UNINSTALL="cp-agent-uninstall.sh" ORCHESTRATION_NAME="orchestration" @@ -336,6 +338,10 @@ while true; do elif [ "$1" = "--cloud-storage" ]; then shift var_cloud_storage=$1 + elif [ "$1" = "--only_unpack_lib64_path" ]; then + shift + USR_LIB_PATH=$1 + var_only_unpack_lib64="set" elif echo "$1" | grep -q ${FORCE_CLEAN_FLAG}; then var_upgrade_mode= elif echo "$1" | grep -q ${DEBUG_FLAG}; then @@ -849,6 +855,13 @@ copy_nginx_metadata_script() cp_exec "chmod +x ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${NGINX_METADDATA_EXTRACTOR_NAME}" } +copy_nginx_fresh_metadata_script() +{ + cp_copy "$NGINX_FRESH_METADATA_EXTRACTOR_PATH" ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${NGINX_FRESH_METADATA_EXTRACTOR_NAME} + cp_exec "chmod 700 ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${NGINX_FRESH_METADATA_EXTRACTOR_NAME}" + cp_exec "chmod +x ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${NGINX_FRESH_METADATA_EXTRACTOR_NAME}" +} + copy_and_run_cloud_metadata_script() { cp_copy "${SCRIPTS_PATH}/$GET_CLOUD_METADATA_PATH" ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${GET_CLOUD_METADATA_PATH} @@ -925,6 +938,19 @@ get_status_content() install_orchestration() { INSTALLATION_TIME=$(date) + + if [ "$var_only_unpack_lib64" = "set" ]; then + cp_exec "mkdir ${USR_LIB_PATH}" + if [ ! -d "$USR_LIB_PATH" ]; then + cp_print "No valid path: ${USR_LIB_PATH}. please do --only_unpack_lib64_path " ${FORCE_STDOUT} + exit 1 + fi + ${INSTALL_COMMAND} lib/*.so* ${USR_LIB_PATH}/ + ${INSTALL_COMMAND} lib/boost/*.so* ${USR_LIB_PATH}/ + cp_print "Done successfully doing only unpacking lib64 to Path: ${USR_LIB_PATH}" ${FORCE_STDOUT} + exit 0 + fi + if [ "$is_smb" != "1" ]; then cp_exec "mkdir -p ${USR_LIB_PATH}/cpnano${VS_LIB_SUB_FOLDER}" else @@ -1038,6 +1064,7 @@ install_orchestration() copy_orchestration_executable copy_k8s_executable copy_nginx_metadata_script + copy_nginx_fresh_metadata_script copy_and_run_cloud_metadata_script install_watchdog "--upgrade" @@ -1133,6 +1160,7 @@ install_orchestration() copy_orchestration_executable copy_k8s_executable copy_nginx_metadata_script + copy_nginx_fresh_metadata_script copy_and_run_cloud_metadata_script install_cp_nano_ctl