From 2cbc7712daf6cf1302e6597cde4849d3049a8432 Mon Sep 17 00:00:00 2001 From: dmiller Date: Sun, 12 Dec 2021 23:42:38 +0000 Subject: [PATCH] Avoid duplicating udp payloads in memory Storing a pointer instead of the whole struct payload enables us to reuse the same struct for as many ports as the payload defines, saving memory as well as the time to copy the struct and its std::string member. This commit also avoids several copy constructions and deletions of the payload vector for each port defined in the file. --- nmap.cc | 2 ++ payload.cc | 54 ++++++++++++++++++++++++++++-------------------------- payload.h | 2 +- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/nmap.cc b/nmap.cc index afd2c09a7..f81be887b 100644 --- a/nmap.cc +++ b/nmap.cc @@ -90,6 +90,7 @@ #include "utils.h" #include "xml.h" #include "scan_lists.h" +#include "payload.h" #ifndef NOLUA #include "nse_main.h" @@ -1789,6 +1790,7 @@ void nmap_free_mem() { cp_free(); free_services(); freeinterfaces(); + free_payloads(); AllProbes::service_scan_free(); traceroute_hop_cache_clear(); nsock_set_default_engine(NULL); diff --git a/payload.cc b/payload.cc index 8d607e2f0..c5ace70f5 100644 --- a/payload.cc +++ b/payload.cc @@ -103,7 +103,8 @@ struct proto_dport { } }; -static std::map > portPayloads; +static std::map > portPayloads; +static std::vector uniquePayloads; // for accounting /* Newlines are significant because keyword directives (like "source") that follow the payload string are significant to the end of the line. */ @@ -199,7 +200,6 @@ static int load_payloads_from_file(FILE *fp) { for (;;) { unsigned short *ports; int count; - std::string payload_data; while (type == TOKEN_NEWLINE) type = next_token(fp, &token); @@ -221,11 +221,12 @@ static int load_payloads_from_file(FILE *fp) { return -1; } - payload_data.clear(); + struct payload *portPayload = new struct payload; + uniquePayloads.push_back(portPayload); for (;;) { type = next_token(fp, &token); if (type == TOKEN_STRING) - payload_data.append(token.text, token.len); + portPayload->data.append(token.text, token.len); else if (type == TOKEN_NEWLINE) ; /* Nothing. */ else @@ -239,34 +240,24 @@ static int load_payloads_from_file(FILE *fp) { } for (int p = 0; p < count; p++) { - std::map >::iterator portPayloadIterator; - std::vector portPayloadVector; - std::vector::iterator portPayloadVectorIterator; + std::vector::const_iterator portPayloadVectorIterator; const struct proto_dport key(IPPROTO_UDP, ports[p]); - struct payload portPayload; bool duplicate = false; - portPayloadIterator = portPayloads.find(key); + std::vector &portPayloadVector = portPayloads[key]; - if (portPayloadIterator != portPayloads.end()) { - portPayloadVector = portPayloadIterator->second; - portPayloadVectorIterator = portPayloadVector.begin(); - - while (portPayloadVectorIterator != portPayloadVector.end()) { - if (portPayloadVectorIterator->data == payload_data) { + for (portPayloadVectorIterator = portPayloadVector.begin(); + portPayloadVectorIterator != portPayloadVector.end(); + portPayloadVectorIterator++) { + if (*portPayloadVectorIterator == portPayload) { log_write(LOG_STDERR, "UDP port payload duplication found on port: %u\n", ports[p]); duplicate = true; break; } - - portPayloadVectorIterator++; - } } if (!duplicate) { - portPayload.data = payload_data; portPayloadVector.push_back(portPayload); - portPayloads[key] = portPayloadVector; if (portPayloadVector.size() > MAX_PAYLOADS_PER_PORT) { fatal("Number of UDP payloads for port %u exceeds the limit of %u.\n", ports[p], MAX_PAYLOADS_PER_PORT); } @@ -312,20 +303,30 @@ int init_payloads(void) { return ret; } +void free_payloads(void) { + std::vector::iterator vec_it; + + for (vec_it = uniquePayloads.begin(); vec_it != uniquePayloads.end(); ++vec_it) { + delete *vec_it; + } + uniquePayloads.clear(); + portPayloads.clear(); +} + /* Get a payload appropriate for the given UDP port. For certain selected ports a payload is returned, and for others a zero-length payload is returned. The length is returned through the length pointer. */ const char *udp_port2payload(u16 dport, size_t *length, u8 index) { static const char *payload_null = ""; - std::map >::const_iterator portPayloadIterator; - std::vector::const_iterator portPayloadVectorIterator; + std::map >::const_iterator portPayloadIterator; + std::vector::const_iterator portPayloadVectorIterator; const proto_dport key(IPPROTO_UDP, dport); int portPayloadVectorSize; portPayloadIterator = portPayloads.find(key); if (portPayloadIterator != portPayloads.end()) { - const std::vector& portPayloadVector = portPayloads.find(key)->second; + const std::vector& portPayloadVector = portPayloads.find(key)->second; portPayloadVectorSize = portPayloadVector.size(); index %= portPayloadVectorSize; @@ -341,8 +342,9 @@ const char *udp_port2payload(u16 dport, size_t *length, u8 index) { assert (index == 0); assert (portPayloadVectorIterator != portPayloadVector.end()); - *length = portPayloadVectorIterator->data.size(); - return portPayloadVectorIterator->data.data(); + const std::string &data = (*portPayloadVectorIterator)->data; + *length = data.size(); + return data.data(); } else { *length = 0; return payload_null; @@ -367,7 +369,7 @@ const char *get_udp_payload(u16 dport, size_t *length, u8 index) { } u8 udp_payload_count(u16 dport) { - std::map >::const_iterator portPayloadIterator; + std::map >::const_iterator portPayloadIterator; const proto_dport key(IPPROTO_UDP, dport); size_t portPayloadVectorSize = 0; diff --git a/payload.h b/payload.h index 23b44a235..b523a9655 100644 --- a/payload.h +++ b/payload.h @@ -71,8 +71,8 @@ #define MAX_PAYLOADS_PER_PORT 0xff const char *get_udp_payload(u16 dport, size_t *length, u8 index); -const char *udp_port2payload(u16 dport, size_t *length, u8 index); u8 udp_payload_count(u16 dport); int init_payloads(void); +void free_payloads(void); #endif /* PAYLOAD_H */