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

Merge from /nmap-exp/david/nmap-mem. This reduces the memory usage of OS

scan by about 95%. (66832396 bytes to 2815061 bytes according to
Massif.)
This commit is contained in:
david
2009-11-23 21:22:07 +00:00
parent ddc1b9b2d1
commit a06b900f00
7 changed files with 540 additions and 616 deletions

View File

@@ -117,7 +117,7 @@ FingerPrintResults::~FingerPrintResults() {
/* Free OS fingerprints of OS scanning was done */ /* Free OS fingerprints of OS scanning was done */
for(i=0; i < numFPs; i++) { for(i=0; i < numFPs; i++) {
freeFingerPrint(FPs[i]); delete(FPs[i]);
FPs[i] = NULL; FPs[i] = NULL;
} }
numFPs = 0; numFPs = 0;
@@ -184,7 +184,8 @@ const char *FingerPrintResults::OmitSubmissionFP() {
/* Goes through fingerprinting results to populate OSR */ /* Goes through fingerprinting results to populate OSR */
void FingerPrintResults::populateClassification() { void FingerPrintResults::populateClassification() {
int printno, classno; std::vector<OS_Classification>::iterator osclass;
int printno;
OSR.OSC_num_perfect_matches = OSR.OSC_num_matches = 0; OSR.OSC_num_perfect_matches = OSR.OSC_num_matches = 0;
OSR.overall_results = OSSCAN_SUCCESS; OSR.overall_results = OSSCAN_SUCCESS;
@@ -198,8 +199,10 @@ void FingerPrintResults::populateClassification() {
for(printno = 0; printno < num_matches; printno++) { for(printno = 0; printno < num_matches; printno++) {
// a single print may have multiple classifications // a single print may have multiple classifications
for(classno = 0; classno < prints[printno]->num_OS_Classifications; classno++) { for (osclass = prints[printno]->OS_class.begin();
if (!classAlreadyExistsInResults(&(prints[printno]->OS_class[classno]))) { osclass != prints[printno]->OS_class.end();
osclass++) {
if (!classAlreadyExistsInResults(&*osclass)) {
// Then we have to add it ... first ensure we have room // Then we have to add it ... first ensure we have room
if (OSR.OSC_num_matches == MAX_FP_RESULTS) { if (OSR.OSC_num_matches == MAX_FP_RESULTS) {
// Out of space ... if the accuracy of this one is 100%, we have a problem // Out of space ... if the accuracy of this one is 100%, we have a problem
@@ -215,7 +218,7 @@ void FingerPrintResults::populateClassification() {
} }
// OK, we will add the new class // OK, we will add the new class
OSR.OSC[OSR.OSC_num_matches] = &(prints[printno]->OS_class[classno]); OSR.OSC[OSR.OSC_num_matches] = &*osclass;
OSR.OSC_Accuracy[OSR.OSC_num_matches] = accuracy[printno]; OSR.OSC_Accuracy[OSR.OSC_num_matches] = accuracy[printno];
if (accuracy[printno] == 1.0) OSR.OSC_num_perfect_matches++; if (accuracy[printno] == 1.0) OSR.OSC_num_perfect_matches++;
OSR.OSC_num_matches++; OSR.OSC_num_matches++;

View File

@@ -94,6 +94,8 @@
#ifndef GLOBAL_STRUCTURES_H #ifndef GLOBAL_STRUCTURES_H
#define GLOBAL_STRUCTURES_H #define GLOBAL_STRUCTURES_H
#include <vector>
class TargetGroup; class TargetGroup;
class Target; class Target;
@@ -155,35 +157,38 @@ struct ftpinfo {
}; };
struct AVal { struct AVal {
char *attribute; const char *attribute;
char value[256]; const char *value;
struct AVal *next;
}; };
struct OS_Classification { struct OS_Classification {
char *OS_Vendor; const char *OS_Vendor;
char *OS_Family; const char *OS_Family;
char *OS_Generation; /* Can be NULL if unclassified */ const char *OS_Generation; /* Can be NULL if unclassified */
char *Device_Type; const char *Device_Type;
}; };
#define MAX_OS_CLASSIFICATIONS_PER_FP 10 struct FingerTest {
typedef struct FingerTest {
char *OS_name;
struct OS_Classification OS_class[MAX_OS_CLASSIFICATIONS_PER_FP];
int num_OS_Classifications;
int line; /* For reference prints, the line # in nmap-os-db */
const char *name; const char *name;
struct AVal *results; std::vector<struct AVal> results;
struct FingerTest *next; };
} FingerPrint;
struct FingerPrint {
int line; /* For reference prints, the line # in nmap-os-db */
char *OS_name;
std::vector<OS_Classification> OS_class;
std::vector<FingerTest> tests;
};
/* This structure contains the important data from the fingerprint /* This structure contains the important data from the fingerprint
database (nmap-os-db) */ database (nmap-os-db) */
typedef struct FingerPrintDB { struct FingerPrintDB {
FingerPrint **prints;
FingerPrint *MatchPoints; FingerPrint *MatchPoints;
} FingerPrintDB; std::vector<FingerPrint *> prints;
FingerPrintDB();
~FingerPrintDB();
};
struct timeout_info { struct timeout_info {
int srtt; /* Smoothed rtt estimate (microseconds) */ int srtt; /* Smoothed rtt estimate (microseconds) */

View File

@@ -1976,7 +1976,7 @@ void nmap_free_mem() {
free_dns_servers(); free_dns_servers();
free_etchosts(); free_etchosts();
if (o.reference_FPs) { if (o.reference_FPs) {
free_fingerprint_file(o.reference_FPs); delete o.reference_FPs;
o.reference_FPs = NULL; o.reference_FPs = NULL;
} }
AllProbes::service_scan_free(); AllProbes::service_scan_free();

455
osscan.cc
View File

@@ -100,6 +100,7 @@
#include "nmap_error.h" #include "nmap_error.h"
#include "utils.h" #include "utils.h"
#include <stdarg.h>
#if TIME_WITH_SYS_TIME #if TIME_WITH_SYS_TIME
# include <sys/time.h> # include <sys/time.h>
# include <time.h> # include <time.h>
@@ -112,27 +113,103 @@
#endif #endif
#include <list> #include <list>
#include <set>
extern NmapOps o; extern NmapOps o;
static struct AVal *getattrbyname(struct AVal *AV, const char *name) { /* Store a string uniquely. The first time this function is called with a
if (!AV) return NULL; certain string, it allocates memory and stores a copy of the string in a
do { static pool. Thereafter it will return a pointer to the saved string instead
if (!strcmp(AV->attribute, name)) of allocating memory for an identical one. */
return AV; const char *string_pool_insert(const char *s)
AV = AV->next; {
} while(AV); static std::set<std::string> pool;
static std::pair<std::set<std::string>::iterator, bool> pair;
pair = pool.insert(s);
return pair.first->c_str();
}
const char *string_pool_substr(const char *s, const char *t)
{
return string_pool_insert(std::string(s, t).c_str());
}
const char *string_pool_substr_strip(const char *s, const char *t) {
while (isspace((int) (unsigned char) *s))
s++;
while (t > s && isspace((int) (unsigned char) *(t - 1)))
t--;
return string_pool_substr(s, t);
}
/* Format a string with sprintf and insert it with string_pool_insert. */
const char *string_pool_sprintf(const char *fmt, ...)
{
const char *s;
char *buf;
int size, n;
va_list ap;
buf = NULL;
size = 32;
/* Loop until we allocate a string big enough for the sprintf. */
for (;;) {
buf = (char *) realloc(buf, size);
assert(buf != NULL);
va_start(ap, fmt);
n = Vsnprintf(buf, size, fmt, ap);
va_end(ap);
if (n < 0)
size = size * 2;
else if (n >= size)
size = n + 1;
else
break;
}
s = string_pool_insert(buf);
free(buf);
return s;
}
FingerPrintDB::FingerPrintDB() : MatchPoints(NULL) {
}
FingerPrintDB::~FingerPrintDB() {
std::vector<FingerPrint *>::iterator current;
if (MatchPoints != NULL)
delete MatchPoints;
for (current = prints.begin(); current != prints.end(); current++)
delete *current;
}
static const struct AVal *getattrbyname(const FingerTest *test, const char *name) {
std::vector<struct AVal>::const_iterator i;
if (test == NULL)
return NULL;
for (i = test->results.begin(); i != test->results.end(); i++) {
if (strcmp(i->attribute, name) == 0)
return &*i;
}
return NULL; return NULL;
} }
static struct AVal *gettestbyname(FingerPrint *FP, const char *name) { static FingerTest *gettestbyname(FingerPrint *FP, const char *name) {
std::vector<FingerTest>::iterator i;
if (!FP) return NULL; if (!FP) return NULL;
do { for (i = FP->tests.begin(); i != FP->tests.end(); i++) {
if (!strcmp(FP->name, name)) if (strcmp(i->name, name) == 0)
return FP->results; return &*i;
FP = FP->next; };
} while(FP);
return NULL; return NULL;
} }
@@ -149,13 +226,13 @@ static struct AVal *gettestbyname(FingerPrint *FP, const char *name) {
case, you may also pass in the group name (SEQ, T1, etc) to have case, you may also pass in the group name (SEQ, T1, etc) to have
that extra info printed. If you pass 0 for verbose, you might as that extra info printed. If you pass 0 for verbose, you might as
well pass NULL for testGroupName as it won't be used. */ well pass NULL for testGroupName as it won't be used. */
static int AVal_match(struct AVal *reference, struct AVal *fprint, struct AVal *points, static int AVal_match(FingerTest *reference, FingerTest *fprint, FingerTest *points,
unsigned long *num_subtests, unsigned long *num_subtests,
unsigned long *num_subtests_succeeded, int shortcut, unsigned long *num_subtests_succeeded, int shortcut,
int verbose, const char *testGroupName) { int verbose, const char *testGroupName) {
struct AVal *current_ref; std::vector<struct AVal>::iterator current_ref;
struct AVal *current_fp; const struct AVal *current_fp;
struct AVal *current_points; const struct AVal *current_points;
unsigned int number, number1; unsigned int number, number1;
unsigned int val; unsigned int val;
char *p, *q, *q1; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */ char *p, *q, *q1; /* OHHHH YEEEAAAAAHHHH!#!@#$!% */
@@ -166,8 +243,9 @@ static int AVal_match(struct AVal *reference, struct AVal *fprint, struct AVal *
int subtests = 0, subtests_succeeded=0; int subtests = 0, subtests_succeeded=0;
int pointsThisTest = 1; int pointsThisTest = 1;
for (current_ref = reference->results.begin();
for(current_ref = reference; current_ref; current_ref = current_ref->next) { current_ref != reference->results.end();
current_ref++) {
current_fp = getattrbyname(fprint, current_ref->attribute); current_fp = getattrbyname(fprint, current_ref->attribute);
if (!current_fp) continue; if (!current_fp) continue;
/* OK, we compare an attribute value in current_fp->value to a /* OK, we compare an attribute value in current_fp->value to a
@@ -255,16 +333,17 @@ static int AVal_match(struct AVal *reference, struct AVal *fprint, struct AVal *
a special "fingerprints" which tells how many points each test is worth. */ a special "fingerprints" which tells how many points each test is worth. */
double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP, double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP,
FingerPrint *MatchPoints, int verbose) { FingerPrint *MatchPoints, int verbose) {
FingerPrint *currentReferenceTest; std::vector<FingerTest>::iterator currentReferenceTest;
struct AVal *currentObservedTest; FingerTest *currentObservedTest;
struct AVal *currentTestMatchPoints; FingerTest *currentTestMatchPoints;
unsigned long num_subtests = 0, num_subtests_succeeded = 0; unsigned long num_subtests = 0, num_subtests_succeeded = 0;
unsigned long new_subtests, new_subtests_succeeded; unsigned long new_subtests, new_subtests_succeeded;
assert(referenceFP); assert(referenceFP);
assert(observedFP); assert(observedFP);
for(currentReferenceTest = referenceFP; currentReferenceTest; for (currentReferenceTest = referenceFP->tests.begin();
currentReferenceTest = currentReferenceTest->next) { currentReferenceTest != referenceFP->tests.end();
currentReferenceTest++) {
currentObservedTest = gettestbyname(observedFP, currentReferenceTest->name); currentObservedTest = gettestbyname(observedFP, currentReferenceTest->name);
if (currentObservedTest) { if (currentObservedTest) {
new_subtests = new_subtests_succeeded = 0; new_subtests = new_subtests_succeeded = 0;
@@ -274,7 +353,7 @@ double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP,
fatal("%s: Failed to locate test %s in MatchPoints directive of fingerprint file", __func__, currentReferenceTest->name); fatal("%s: Failed to locate test %s in MatchPoints directive of fingerprint file", __func__, currentReferenceTest->name);
} else currentTestMatchPoints = NULL; } else currentTestMatchPoints = NULL;
AVal_match(currentReferenceTest->results, currentObservedTest, currentTestMatchPoints, AVal_match(&*currentReferenceTest, currentObservedTest, currentTestMatchPoints,
&new_subtests, &new_subtests_succeeded, 0, verbose, currentReferenceTest->name); &new_subtests, &new_subtests_succeeded, 0, verbose, currentReferenceTest->name);
num_subtests += new_subtests; num_subtests += new_subtests;
num_subtests_succeeded += new_subtests_succeeded; num_subtests_succeeded += new_subtests_succeeded;
@@ -293,14 +372,11 @@ double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP,
the maximum that fits in a FingerPrintResults class. */ the maximum that fits in a FingerPrintResults class. */
void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR, void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
FingerPrintDB *DB, double accuracy_threshold) { FingerPrintDB *DB, double accuracy_threshold) {
int i;
double FPR_entrance_requirement = accuracy_threshold; /* accuracy must be double FPR_entrance_requirement = accuracy_threshold; /* accuracy must be
at least this big at least this big
to be added to the to be added to the
list */ list */
FingerPrint **reference_FPs = DB->prints; std::vector<FingerPrint *>::iterator current_os;
FingerPrint *current_os;
double acc; double acc;
int state; int state;
int skipfp; int skipfp;
@@ -315,18 +391,17 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
FPR->overall_results = OSSCAN_SUCCESS; FPR->overall_results = OSSCAN_SUCCESS;
for(i = 0; reference_FPs[i]; i++) { for (current_os = DB->prints.begin(); current_os != DB->prints.end(); current_os++) {
current_os = reference_FPs[i];
skipfp = 0; skipfp = 0;
acc = compare_fingerprints(current_os, FP, DB->MatchPoints, 0); acc = compare_fingerprints(*current_os, FP, DB->MatchPoints, 0);
/* error("Comp to %s: %li/%li=%f", o.reference_FPs1[i]->OS_name, num_subtests_succeeded, num_subtests, acc); */ /* error("Comp to %s: %li/%li=%f", o.reference_FPs1[i]->OS_name, num_subtests_succeeded, num_subtests, acc); */
if (acc >= FPR_entrance_requirement || acc == 1.0) { if (acc >= FPR_entrance_requirement || acc == 1.0) {
state = 0; state = 0;
for(idx=0; idx < FPR->num_matches; idx++) { for(idx=0; idx < FPR->num_matches; idx++) {
if (strcmp(FPR->prints[idx]->OS_name, current_os->OS_name) == 0) { if (strcmp(FPR->prints[idx]->OS_name, (*current_os)->OS_name) == 0) {
if (FPR->accuracy[idx] >= acc) { if (FPR->accuracy[idx] >= acc) {
skipfp = 1; /* Skip it -- a higher version is already in list */ skipfp = 1; /* Skip it -- a higher version is already in list */
} else { } else {
@@ -370,7 +445,7 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
/* OK, I insert the sucker into the next slot ... */ /* OK, I insert the sucker into the next slot ... */
tmp_acc = FPR->accuracy[idx+1]; tmp_acc = FPR->accuracy[idx+1];
tmp_FP = FPR->prints[idx+1]; tmp_FP = FPR->prints[idx+1];
FPR->prints[idx+1] = current_os; FPR->prints[idx+1] = *current_os;
FPR->accuracy[idx+1] = acc; FPR->accuracy[idx+1] = acc;
state = 1; state = 1;
} }
@@ -396,21 +471,6 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
return; return;
} }
void freeFingerPrint(FingerPrint *FP) {
FingerPrint *currentFP;
FingerPrint *nextFP;
if (!FP) return;
for(currentFP = FP; currentFP; currentFP = nextFP) {
nextFP = currentFP->next;
if (currentFP->results)
free(currentFP->results);
free(currentFP);
}
return;
}
static const char *dist_method_fp_string(enum dist_calc_method method) static const char *dist_method_fp_string(enum dist_calc_method method)
{ {
const char *s = ""; const char *s = "";
@@ -482,50 +542,76 @@ static void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
macbuf, (int) timep, NMAP_PLATFORM); macbuf, (int) timep, NMAP_PLATFORM);
} }
/* Puts a textual representation of the chain of AVals beginning with AV in s. /* Puts a textual representation of the test in s.
No more than n bytes will be written. Unless n is 0, the string is always No more than n bytes will be written. Unless n is 0, the string is always
null-terminated. Returns the number of bytes written, excluding the null-terminated. Returns the number of bytes written, excluding the
terminator. */ terminator. */
static int AVal2str(const struct AVal *AV, char *s, size_t n) { static int test2str(const FingerTest *test, char *s, size_t n) {
std::vector<struct AVal>::const_iterator av;
char *p; char *p;
char *end; char *end;
size_t len; size_t len;
if (AV == NULL) { if (n == 0)
if (n > 0)
*s = '\0';
return 0; return 0;
}
p = s; p = s;
end = s + n - 1; end = s + n - 1;
for ( ; AV != NULL; AV = AV->next) {
if (p >= end) len = strlen(test->name);
break; if (p + len > end)
/* Put a separator in front of every attribute-value pair but the first. */ goto error;
if (p != s)
*p++ = '%'; memcpy(p, test->name, len);
len = MIN((ptrdiff_t) strlen(AV->attribute), end - p);
memcpy(p, AV->attribute, len);
p += len; p += len;
if (p >= end) if (p + 1 > end)
break; goto error;
*p++ = '(';
for (av = test->results.begin(); av != test->results.end(); av++) {
if (av != test->results.begin()) {
if (p + 1 > end)
goto error;
*p++ = '%';
}
len = strlen(av->attribute);
if (p + len > end)
goto error;
memcpy(p, av->attribute, len);
p += len;
if (p + 1 > end)
goto error;
*p++ = '='; *p++ = '=';
len = MIN((ptrdiff_t) strlen(AV->value), end - p); len = strlen(av->value);
memcpy(p, AV->value, len); if (p + len > end)
goto error;
memcpy(p, av->value, len);
p += len; p += len;
} }
if (p + 1 > end)
goto error;
*p++ = ')';
*p = '\0'; *p = '\0';
return p - s; return p - s;
error:
if (n > 0)
*s = '\0';
return -1;
} }
static struct AVal *str2AVal(char *str) { static std::vector<struct AVal> str2AVal(char *str) {
int i = 1; int i = 1;
int count = 1; int count = 1;
char *q = str, *p=str; char *q = str, *p=str;
struct AVal *AVs; std::vector<struct AVal> AVs;
if (!*str) return NULL;
if (!*str)
return std::vector<struct AVal>();
/* count the AVals */ /* count the AVals */
while((q = strchr(q, '%'))) { while((q = strchr(q, '%'))) {
@@ -533,14 +619,16 @@ static struct AVal *str2AVal(char *str) {
q++; q++;
} }
AVs = (struct AVal *) safe_zalloc(count * sizeof(struct AVal)); AVs.reserve(count);
for(i=0; i < count; i++) { for(i=0; i < count; i++) {
struct AVal av;
q = strchr(p, '='); q = strchr(p, '=');
if (!q) { if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-db file", str); fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
} }
*q = '\0'; *q = '\0';
AVs[i].attribute = strdup(p); av.attribute = string_pool_insert(p);
p = q+1; p = q+1;
if (i != count - 1) { if (i != count - 1) {
q = strchr(p, '%'); q = strchr(p, '%');
@@ -548,31 +636,33 @@ static struct AVal *str2AVal(char *str) {
fatal("Parse error with AVal string (%s) in nmap-os-db file", str); fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
} }
*q = '\0'; *q = '\0';
AVs[i].next = &AVs[i+1];
} }
Strncpy(AVs[i].value, p, sizeof(AVs[i].value)); av.value = string_pool_insert(p);
p = q + 1; p = q + 1;
AVs.push_back(av);
} }
return AVs; return AVs;
} }
/* Compare two AVal chains literally, without evaluating the value of either one /* Compare two AVal chains literally, without evaluating the value of either one
as an expression. This is used by mergeFPs. Unlike with AVal_match, it is as an expression. This is used by mergeFPs. Unlike with AVal_match, it is
always the case that AVal_match_literal(a, b) == AVal_match_literal(b, a). */ always the case that AVal_match_literal(a, b) == AVal_match_literal(b, a). */
static bool AVal_match_literal(struct AVal *a, struct AVal *b) { static bool test_match_literal(const FingerTest *a, const FingerTest *b) {
struct AVal *av_a, *av_b; std::vector<struct AVal>::const_iterator i;
const struct AVal *av;
/* Check that b contains all the AVals in a, with the same values. */ /* Check that b contains all the AVals in a, with the same values. */
for (av_a = a; av_a != NULL; av_a = av_a->next) { for (i = a->results.begin(); i != a->results.end(); i++) {
av_b = getattrbyname(b, av_a->attribute); av = getattrbyname(b, i->attribute);
if (av_b == NULL || strcmp(av_a->value, av_b->value) != 0) if (av == NULL || strcmp(i->value, av->value) != 0)
return false; return false;
} }
/* Check that a contains all the AVals in b, with the same values. */ /* Check that a contains all the AVals in b, with the same values. */
for (av_b = a; av_b != NULL; av_b = av_b->next) { for (i = b->results.begin(); i != b->results.end(); i++) {
av_a = getattrbyname(a, av_b->attribute); av = getattrbyname(a, i->attribute);
if (av_a == NULL || strcmp(av_a->value, av_b->value) != 0) if (av == NULL || strcmp(i->value, av->value) != 0)
return false; return false;
} }
@@ -633,7 +723,7 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
char *end = str + sizeof(str) - 1; /* Last byte allowed to write into */ char *end = str + sizeof(str) - 1; /* Last byte allowed to write into */
std::list<const FingerTest *> tests; std::list<const FingerTest *> tests;
std::list<const FingerTest *>::iterator iter; std::list<const FingerTest *>::iterator iter;
const FingerTest *ft; std::vector<FingerTest>::iterator ft;
if (numFPs <= 0) if (numFPs <= 0)
return "(None)"; return "(None)";
@@ -642,8 +732,8 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
/* Copy the tests from each fingerprint into a flat list. */ /* Copy the tests from each fingerprint into a flat list. */
for (i = 0; i < numFPs; i++) { for (i = 0; i < numFPs; i++) {
for (ft = FPs[i]; ft != NULL; ft = ft->next) for (ft = FPs[i]->tests.begin(); ft != FPs[i]->tests.end(); ft++)
tests.push_back(ft); tests.push_back(&*ft);
} }
/* Put the tests in the proper order and ensure that tests with identical /* Put the tests in the proper order and ensure that tests with identical
@@ -660,7 +750,7 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
while (tmp_i != tests.end() && strcmp((*iter)->name, (*tmp_i)->name) == 0) { while (tmp_i != tests.end() && strcmp((*iter)->name, (*tmp_i)->name) == 0) {
next = tmp_i; next = tmp_i;
next++; next++;
if (AVal_match_literal((*iter)->results, (*tmp_i)->results)) { if (test_match_literal(*iter, *tmp_i)) {
/* This is a duplicate test. Remove it. */ /* This is a duplicate test. Remove it. */
tests.erase(tmp_i); tests.erase(tmp_i);
} }
@@ -670,17 +760,16 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
/* A safety check to make sure that no tests were lost in merging. */ /* A safety check to make sure that no tests were lost in merging. */
for (i = 0; i < numFPs; i++) { for (i = 0; i < numFPs; i++) {
for (ft = FPs[i]; ft != NULL; ft = ft->next) { for (ft = FPs[i]->tests.begin(); ft != FPs[i]->tests.end(); ft++) {
for (iter = tests.begin(); iter != tests.end(); iter++) { for (iter = tests.begin(); iter != tests.end(); iter++) {
if (strcmp((*iter)->name, ft->name) == 0 if (strcmp((*iter)->name, ft->name) == 0 && test_match_literal(*iter, &*ft)) {
&& AVal_match_literal((*iter)->results, ft->results)) {
break; break;
} }
} }
if (iter == tests.end()) { if (iter == tests.end()) {
char buf[200]; char buf[200];
AVal2str(ft->results, buf, sizeof(buf)); test2str(&*ft, buf, sizeof(buf));
fatal("The test %s(%s) was somehow lost in %s.\n", ft->name, buf, __func__); fatal("The test %s was somehow lost in %s.\n", buf, __func__);
} }
} }
} }
@@ -698,29 +787,21 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
/* Append the string representation of each test to the result string. */ /* Append the string representation of each test to the result string. */
for (iter = tests.begin(); iter != tests.end(); iter++) { for (iter = tests.begin(); iter != tests.end(); iter++) {
size_t len; int len;
ft = *iter; len = test2str(*iter, p, end - p + 1);
len = MIN((ptrdiff_t) strlen(ft->name), (end - p)); if (len == -1)
memcpy(p, ft->name, len);
p += len;
if (p >= end)
break; break;
*p++ = '(';
len = AVal2str(ft->results, p, end - p + 1);
p += len; p += len;
if (p >= end)
break;
*p++ = ')';
if (!wrapit) { if (!wrapit) {
if (p >= end) if (p + 1 > end)
break; break;
*p++ = '\n'; *p++ = '\n';
} }
} }
/* If we bailed out of the loop early it was because we ran out of space. */ /* If we bailed out of the loop early it was because we ran out of space. */
if (iter != tests.end() || p > end) if (iter != tests.end())
fatal("Merged fingerprint too long in %s.\n", __func__); fatal("Merged fingerprint too long in %s.\n", __func__);
*p = '\0'; *p = '\0';
@@ -755,86 +836,51 @@ return str;
const char *fp2ascii(FingerPrint *FP) { const char *fp2ascii(FingerPrint *FP) {
static char str[2048]; static char str[2048];
FingerPrint *current; std::vector<FingerTest>::iterator iter;
struct AVal *AV;
char *p = str; char *p = str;
memset(str, 0, sizeof(str));
if (!FP) return "(None)"; if (!FP) return "(None)";
for(current = FP; current ; current = current->next) { for (iter = FP->tests.begin(); iter != FP->tests.end(); iter++) {
Strncpy(p, current->name, sizeof(str) - (p-str)); int len;
p += strlen(p);
assert(p-str < (int) sizeof(str) - 30); len = test2str(&*iter, p, sizeof(str) - (p - str));
*p++='('; if (len == -1)
for(AV = current->results; AV; AV = AV->next) { break;
Strncpy(p, AV->attribute, sizeof(str) - (p-str)); p += len;
p += strlen(p); if (p + 1 > str + sizeof(str))
assert(p-str < (int) sizeof(str) - 30); break;
*p++='=';
Strncpy(p, AV->value, sizeof(str) - (p-str));
p += strlen(p);
assert(p-str < (int) sizeof(str) - 30);
*p++ = '%';
}
if(*(p-1) != '(')
p--; /* Kill the final & */
*p++ = ')';
*p++ = '\n'; *p++ = '\n';
} }
*p = '\0'; *p = '\0';
return str; return str;
} }
/* Return a zero-terminated copy of the substring that starts at p and ends at
q, with leading and trailing whitespace stripped. The returned string is
allocated with cp_alloc. */
static char *substrstrip(const char *p, const char *q) {
char *s;
assert(p <= q);
while (isspace((int) (unsigned char) *p))
p++;
while (q > p && isspace((int) (unsigned char) *(q - 1)))
q--;
s = (char *) cp_alloc(q - p + 1);
memcpy(s, p, q - p);
s[q - p] = '\0';
return s;
}
/* Parse a 'Class' line found in the fingerprint file into the current /* Parse a 'Class' line found in the fingerprint file into the current
FP. Classno is the number of 'class' lines found so far in the FP. Classno is the number of 'class' lines found so far in the
current fingerprint. The function quits if there is a parse error */ current fingerprint. The function quits if there is a parse error */
static void parse_classline(FingerPrint *FP, char *thisline, int lineno, static void parse_classline(FingerPrint *FP, char *thisline, int lineno) {
int *classno) {
const char *begin, *end; const char *begin, *end;
struct OS_Classification *os_class; struct OS_Classification os_class;
if (!thisline || strncmp(thisline, "Class ", 6) != 0) if (!thisline || strncmp(thisline, "Class ", 6) != 0)
fatal("Bogus line #%d (%s) passed to %s()", lineno, thisline, __func__); fatal("Bogus line #%d (%s) passed to %s()", lineno, thisline, __func__);
if (*classno >= MAX_OS_CLASSIFICATIONS_PER_FP)
fatal("Too many Class lines in fingerprint (line %d: %s), remove some or increase MAX_OS_CLASSIFICATIONS_PER_FP", lineno, thisline);
os_class = &FP->OS_class[*classno];
/* First let's get the vendor name. */ /* First let's get the vendor name. */
begin = thisline + 6; begin = thisline + 6;
end = strchr(begin, '|'); end = strchr(begin, '|');
if (end == NULL) if (end == NULL)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
os_class->OS_Vendor = substrstrip(begin, end); os_class.OS_Vendor = string_pool_substr_strip(begin, end);
/* Next comes the OS family. */ /* Next comes the OS family. */
begin = end + 1; begin = end + 1;
end = strchr(begin, '|'); end = strchr(begin, '|');
if (end == NULL) if (end == NULL)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
os_class->OS_Family = substrstrip(begin, end); os_class.OS_Family = string_pool_substr_strip(begin, end);
/* And now the the OS generation. */ /* And now the the OS generation. */
begin = end + 1; begin = end + 1;
@@ -846,17 +892,16 @@ static void parse_classline(FingerPrint *FP, char *thisline, int lineno,
while (isspace((int) (unsigned char) *begin)) while (isspace((int) (unsigned char) *begin))
begin++; begin++;
if (begin < end) if (begin < end)
os_class->OS_Generation = substrstrip(begin, end); os_class.OS_Generation = string_pool_substr_strip(begin, end);
else else
os_class->OS_Generation = NULL; os_class.OS_Generation = NULL;
/* And finally the device type. We look for '\0' instead of '|'. */ /* And finally the device type. We look for '\0' instead of '|'. */
begin = end + 1; begin = end + 1;
end = strchr(begin, '\0'); end = strchr(begin, '\0');
os_class->Device_Type = substrstrip(begin, end); os_class.Device_Type = string_pool_substr_strip(begin, end);
(*classno)++; FP->OS_class.push_back(os_class);
FP->num_OS_Classifications++;
} }
/* Parses a single fingerprint from the memory region given. If a /* Parses a single fingerprint from the memory region given. If a
@@ -868,15 +913,12 @@ static void parse_classline(FingerPrint *FP, char *thisline, int lineno,
it is used by fingerprint utilities that link with Nmap object files. */ it is used by fingerprint utilities that link with Nmap object files. */
FingerPrint *parse_single_fingerprint(char *fprint_orig) { FingerPrint *parse_single_fingerprint(char *fprint_orig) {
int lineno = 0; int lineno = 0;
int classno = 0; /* Number of Class lines dealt with so far */
char *p, *q; char *p, *q;
char *thisline, *nextline; char *thisline, *nextline;
char *fprint = strdup(fprint_orig); /* Make a copy we can futz with */ char *fprint = strdup(fprint_orig); /* Make a copy we can futz with */
FingerPrint *FP; FingerPrint *FP;
FingerPrint *current; /* Since a fingerprint is really a linked list of
FingerPrint structures */
current = FP = (FingerPrint *) safe_zalloc(sizeof(FingerPrint)); FP = new FingerPrint;
thisline = fprint; thisline = fprint;
@@ -914,15 +956,12 @@ FingerPrint *parse_single_fingerprint(char *fprint_orig) {
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
} else if (strncmp(thisline, "Class ", 6) == 0) { } else if (strncmp(thisline, "Class ", 6) == 0) {
parse_classline(FP, thisline, lineno, &classno); parse_classline(FP, thisline, lineno);
} else if ((q = strchr(thisline, '('))) { } else if ((q = strchr(thisline, '('))) {
FingerTest test;
*q = '\0'; *q = '\0';
if(current->name) { test.name = string_pool_insert(thisline);
current->next = (FingerPrint *) safe_zalloc(sizeof(FingerPrint));
current = current->next;
}
current->name = strdup(thisline);
p = q+1; p = q+1;
*q = '('; *q = '(';
q = strchr(p, ')'); q = strchr(p, ')');
@@ -930,7 +969,8 @@ FingerPrint *parse_single_fingerprint(char *fprint_orig) {
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
} }
*q = '\0'; *q = '\0';
current->results = str2AVal(p); test.results = str2AVal(p);
FP->tests.push_back(test);
} else { } else {
fatal("Parse error line line #%d of fingerprint", lineno); fatal("Parse error line line #%d of fingerprint", lineno);
} }
@@ -946,71 +986,22 @@ FingerPrint *parse_single_fingerprint(char *fprint_orig) {
} }
void free_fingerprint_file(FingerPrintDB *DB) {
FingerPrint **FPs = DB->prints;
FingerPrint **current;
FingerPrint *c, *d;
struct AVal *avc;
struct AVal *avd;
for(current = FPs; *current != NULL; current++){
for(c = *current; c; c=d){
d = c->next;
if(c->name)
free((void*)c->name); //strdup
if(c->results){
for(avc = c->results; avc; avc = avd) {
avd = avc->next;
if(avc->attribute)
free(avc->attribute);
}
free(c->results);
}
free(c);
}
}
free(FPs);
if (DB->MatchPoints) {
for(c = DB->MatchPoints; c; c=d){
d = c->next;
if(c->name)
free((void*)c->name); //strdup
if(c->results){
for(avc = c->results; avc; avc = avd) {
avd = avc->next;
if(avc->attribute)
free(avc->attribute);
}
free(c->results);
}
free(c);
}
}
free(DB);
}
FingerPrintDB *parse_fingerprint_file(const char *fname) { FingerPrintDB *parse_fingerprint_file(const char *fname) {
FingerPrintDB *DB = NULL; FingerPrintDB *DB = NULL;
FingerPrint *current; FingerPrint *current;
FILE *fp; FILE *fp;
int max_records = 4096;
char line[2048]; char line[2048];
int numrecords = 0;
int lineno = 0; int lineno = 0;
bool parsingMatchPoints = false; bool parsingMatchPoints = false;
int classno = 0; /* Number of Class lines dealt with so far */ int classno = 0; /* Number of Class lines dealt with so far */
DB = (FingerPrintDB *) safe_zalloc(sizeof(FingerPrintDB)); DB = new FingerPrintDB;
char *p, *q; /* OH YEAH!!!! */ char *p, *q; /* OH YEAH!!!! */
if (!DB) fatal("non-allocated DB passed to %s", __func__); if (!DB) fatal("non-allocated DB passed to %s", __func__);
DB->prints = (FingerPrint **) safe_zalloc(sizeof(FingerPrint *) * max_records);
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if (!fp) fatal("Unable to open Nmap fingerprint file: %s", fname); if (!fp) fatal("Unable to open Nmap fingerprint file: %s", fname);
@@ -1033,13 +1024,13 @@ while(fgets(line, sizeof(line), fp)) {
continue; continue;
} }
current = (FingerPrint *) safe_zalloc(sizeof(FingerPrint)); current = new FingerPrint;
if (parsingMatchPoints) { if (parsingMatchPoints) {
current->OS_name = NULL; current->OS_name = NULL;
DB->MatchPoints = current; DB->MatchPoints = current;
} else { } else {
DB->prints[numrecords] = current; DB->prints.push_back(current);
p = line + 12; p = line + 12;
while(*p && isspace((int) (unsigned char) *p)) p++; while(*p && isspace((int) (unsigned char) *p)) p++;
@@ -1069,8 +1060,9 @@ while(fgets(line, sizeof(line), fp)) {
if (!strncmp(line, "FingerPrint ",12)) { if (!strncmp(line, "FingerPrint ",12)) {
goto fparse; goto fparse;
} else if (strncmp(line, "Class ", 6) == 0) { } else if (strncmp(line, "Class ", 6) == 0) {
parse_classline(current, line, lineno, &classno); parse_classline(current, line, lineno);
} else { } else {
FingerTest test;
p = line; p = line;
q = strchr(line, '('); q = strchr(line, '(');
if (!q) { if (!q) {
@@ -1078,11 +1070,7 @@ while(fgets(line, sizeof(line), fp)) {
goto top; goto top;
} }
*q = '\0'; *q = '\0';
if(current->name) { test.name = string_pool_insert(p);
current->next = (FingerPrint *) safe_zalloc(sizeof(FingerPrint));
current = current->next;
}
current->name = strdup(p);
p = q+1; p = q+1;
*q = '('; *q = '(';
q = strchr(p, ')'); q = strchr(p, ')');
@@ -1091,17 +1079,12 @@ while(fgets(line, sizeof(line), fp)) {
goto top; goto top;
} }
*q = '\0'; *q = '\0';
current->results = str2AVal(p); test.results = str2AVal(p);
current->tests.push_back(test);
} }
} }
/* printf("Read in fingerprint:\n%s\n", fp2ascii(DB->prints[numrecords])); */
if (!parsingMatchPoints)
numrecords++;
if (numrecords >= max_records)
fatal("Too many OS fingerprints -- 0verflow");
} }
fclose(fp); fclose(fp);
DB->prints[numrecords] = NULL;
return DB; return DB;
} }

View File

@@ -110,6 +110,13 @@
/* moved to global_structures.h */ /* moved to global_structures.h */
/********************** PROTOTYPES ***********************************/ /********************** PROTOTYPES ***********************************/
/* The OS database consists of many small strings, many of which appear
thousands of times. It pays to allocate memory only once for each unique
string, and have all references point at the one allocated value. */
const char *string_pool_insert(const char *s);
const char *string_pool_sprintf(const char *fmt, ...);
const char *fp2ascii(FingerPrint *FP); const char *fp2ascii(FingerPrint *FP);
/* Parses a single fingerprint from the memory region given. If a /* Parses a single fingerprint from the memory region given. If a

File diff suppressed because it is too large Load Diff

View File

@@ -1493,8 +1493,8 @@ void write_host_status(Target * currenths, int resolve_all) {
that only unique entries are added. Also note that *numentries is that only unique entries are added. Also note that *numentries is
incremented if the candidate is added. arrsize is the number of incremented if the candidate is added. arrsize is the number of
char * members that fit into arr */ char * members that fit into arr */
static int addtochararrayifnew(char *arr[], int *numentries, int arrsize, static int addtochararrayifnew(const char *arr[], int *numentries, int arrsize,
char *candidate) { const char *candidate) {
int i; int i;
// First lets see if the member already exists // First lets see if the member already exists
@@ -1520,7 +1520,7 @@ static void printosclassificationoutput(const struct
bool guess) { bool guess) {
int classno, i, familyno; int classno, i, familyno;
int overflow = 0; /* Whether we have too many devices to list */ int overflow = 0; /* Whether we have too many devices to list */
char *types[MAX_OS_CLASSMEMBERS]; const char *types[MAX_OS_CLASSMEMBERS];
char fullfamily[MAX_OS_CLASSMEMBERS][128]; // "[vendor] [os family]" char fullfamily[MAX_OS_CLASSMEMBERS][128]; // "[vendor] [os family]"
double familyaccuracy[MAX_OS_CLASSMEMBERS]; // highest accuracy for this fullfamily double familyaccuracy[MAX_OS_CLASSMEMBERS]; // highest accuracy for this fullfamily
char familygenerations[MAX_OS_CLASSMEMBERS][48]; // example: "4.X|5.X|6.X" char familygenerations[MAX_OS_CLASSMEMBERS][48]; // example: "4.X|5.X|6.X"