1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 12:41:29 +00:00

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.
This commit is contained in:
dmiller
2021-12-12 23:42:38 +00:00
parent 2cea59aca0
commit 2cbc7712da
3 changed files with 31 additions and 27 deletions

View File

@@ -90,6 +90,7 @@
#include "utils.h" #include "utils.h"
#include "xml.h" #include "xml.h"
#include "scan_lists.h" #include "scan_lists.h"
#include "payload.h"
#ifndef NOLUA #ifndef NOLUA
#include "nse_main.h" #include "nse_main.h"
@@ -1789,6 +1790,7 @@ void nmap_free_mem() {
cp_free(); cp_free();
free_services(); free_services();
freeinterfaces(); freeinterfaces();
free_payloads();
AllProbes::service_scan_free(); AllProbes::service_scan_free();
traceroute_hop_cache_clear(); traceroute_hop_cache_clear();
nsock_set_default_engine(NULL); nsock_set_default_engine(NULL);

View File

@@ -103,7 +103,8 @@ struct proto_dport {
} }
}; };
static std::map<struct proto_dport, std::vector<struct payload> > portPayloads; static std::map<struct proto_dport, std::vector<struct payload *> > portPayloads;
static std::vector<struct payload *> uniquePayloads; // for accounting
/* Newlines are significant because keyword directives (like "source") that /* Newlines are significant because keyword directives (like "source") that
follow the payload string are significant to the end of the line. */ 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 (;;) { for (;;) {
unsigned short *ports; unsigned short *ports;
int count; int count;
std::string payload_data;
while (type == TOKEN_NEWLINE) while (type == TOKEN_NEWLINE)
type = next_token(fp, &token); type = next_token(fp, &token);
@@ -221,11 +221,12 @@ static int load_payloads_from_file(FILE *fp) {
return -1; return -1;
} }
payload_data.clear(); struct payload *portPayload = new struct payload;
uniquePayloads.push_back(portPayload);
for (;;) { for (;;) {
type = next_token(fp, &token); type = next_token(fp, &token);
if (type == TOKEN_STRING) if (type == TOKEN_STRING)
payload_data.append(token.text, token.len); portPayload->data.append(token.text, token.len);
else if (type == TOKEN_NEWLINE) else if (type == TOKEN_NEWLINE)
; /* Nothing. */ ; /* Nothing. */
else else
@@ -239,34 +240,24 @@ static int load_payloads_from_file(FILE *fp) {
} }
for (int p = 0; p < count; p++) { for (int p = 0; p < count; p++) {
std::map<struct proto_dport, std::vector<struct payload> >::iterator portPayloadIterator; std::vector<struct payload *>::const_iterator portPayloadVectorIterator;
std::vector<struct payload> portPayloadVector;
std::vector<struct payload>::iterator portPayloadVectorIterator;
const struct proto_dport key(IPPROTO_UDP, ports[p]); const struct proto_dport key(IPPROTO_UDP, ports[p]);
struct payload portPayload;
bool duplicate = false; bool duplicate = false;
portPayloadIterator = portPayloads.find(key); std::vector<struct payload *> &portPayloadVector = portPayloads[key];
if (portPayloadIterator != portPayloads.end()) { for (portPayloadVectorIterator = portPayloadVector.begin();
portPayloadVector = portPayloadIterator->second; portPayloadVectorIterator != portPayloadVector.end();
portPayloadVectorIterator = portPayloadVector.begin(); portPayloadVectorIterator++) {
if (*portPayloadVectorIterator == portPayload) {
while (portPayloadVectorIterator != portPayloadVector.end()) {
if (portPayloadVectorIterator->data == payload_data) {
log_write(LOG_STDERR, "UDP port payload duplication found on port: %u\n", ports[p]); log_write(LOG_STDERR, "UDP port payload duplication found on port: %u\n", ports[p]);
duplicate = true; duplicate = true;
break; break;
} }
portPayloadVectorIterator++;
}
} }
if (!duplicate) { if (!duplicate) {
portPayload.data = payload_data;
portPayloadVector.push_back(portPayload); portPayloadVector.push_back(portPayload);
portPayloads[key] = portPayloadVector;
if (portPayloadVector.size() > MAX_PAYLOADS_PER_PORT) { 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); 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; return ret;
} }
void free_payloads(void) {
std::vector<struct payload *>::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 /* 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 a payload is returned, and for others a zero-length payload is returned. The
length is returned through the length pointer. */ length is returned through the length pointer. */
const char *udp_port2payload(u16 dport, size_t *length, u8 index) { const char *udp_port2payload(u16 dport, size_t *length, u8 index) {
static const char *payload_null = ""; static const char *payload_null = "";
std::map<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator; std::map<struct proto_dport, std::vector<struct payload *> >::const_iterator portPayloadIterator;
std::vector<struct payload>::const_iterator portPayloadVectorIterator; std::vector<struct payload *>::const_iterator portPayloadVectorIterator;
const proto_dport key(IPPROTO_UDP, dport); const proto_dport key(IPPROTO_UDP, dport);
int portPayloadVectorSize; int portPayloadVectorSize;
portPayloadIterator = portPayloads.find(key); portPayloadIterator = portPayloads.find(key);
if (portPayloadIterator != portPayloads.end()) { if (portPayloadIterator != portPayloads.end()) {
const std::vector<struct payload>& portPayloadVector = portPayloads.find(key)->second; const std::vector<struct payload *>& portPayloadVector = portPayloads.find(key)->second;
portPayloadVectorSize = portPayloadVector.size(); portPayloadVectorSize = portPayloadVector.size();
index %= portPayloadVectorSize; index %= portPayloadVectorSize;
@@ -341,8 +342,9 @@ const char *udp_port2payload(u16 dport, size_t *length, u8 index) {
assert (index == 0); assert (index == 0);
assert (portPayloadVectorIterator != portPayloadVector.end()); assert (portPayloadVectorIterator != portPayloadVector.end());
*length = portPayloadVectorIterator->data.size(); const std::string &data = (*portPayloadVectorIterator)->data;
return portPayloadVectorIterator->data.data(); *length = data.size();
return data.data();
} else { } else {
*length = 0; *length = 0;
return payload_null; 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) { u8 udp_payload_count(u16 dport) {
std::map<struct proto_dport, std::vector<struct payload> >::const_iterator portPayloadIterator; std::map<struct proto_dport, std::vector<struct payload *> >::const_iterator portPayloadIterator;
const proto_dport key(IPPROTO_UDP, dport); const proto_dport key(IPPROTO_UDP, dport);
size_t portPayloadVectorSize = 0; size_t portPayloadVectorSize = 0;

View File

@@ -71,8 +71,8 @@
#define MAX_PAYLOADS_PER_PORT 0xff #define MAX_PAYLOADS_PER_PORT 0xff
const char *get_udp_payload(u16 dport, size_t *length, u8 index); 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); u8 udp_payload_count(u16 dport);
int init_payloads(void); int init_payloads(void);
void free_payloads(void);
#endif /* PAYLOAD_H */ #endif /* PAYLOAD_H */