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:
@@ -117,7 +117,7 @@ FingerPrintResults::~FingerPrintResults() {
|
||||
|
||||
/* Free OS fingerprints of OS scanning was done */
|
||||
for(i=0; i < numFPs; i++) {
|
||||
freeFingerPrint(FPs[i]);
|
||||
delete(FPs[i]);
|
||||
FPs[i] = NULL;
|
||||
}
|
||||
numFPs = 0;
|
||||
@@ -184,7 +184,8 @@ const char *FingerPrintResults::OmitSubmissionFP() {
|
||||
|
||||
/* Goes through fingerprinting results to populate OSR */
|
||||
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.overall_results = OSSCAN_SUCCESS;
|
||||
@@ -198,8 +199,10 @@ void FingerPrintResults::populateClassification() {
|
||||
|
||||
for(printno = 0; printno < num_matches; printno++) {
|
||||
// a single print may have multiple classifications
|
||||
for(classno = 0; classno < prints[printno]->num_OS_Classifications; classno++) {
|
||||
if (!classAlreadyExistsInResults(&(prints[printno]->OS_class[classno]))) {
|
||||
for (osclass = prints[printno]->OS_class.begin();
|
||||
osclass != prints[printno]->OS_class.end();
|
||||
osclass++) {
|
||||
if (!classAlreadyExistsInResults(&*osclass)) {
|
||||
// Then we have to add it ... first ensure we have room
|
||||
if (OSR.OSC_num_matches == MAX_FP_RESULTS) {
|
||||
// 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
|
||||
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];
|
||||
if (accuracy[printno] == 1.0) OSR.OSC_num_perfect_matches++;
|
||||
OSR.OSC_num_matches++;
|
||||
|
||||
@@ -94,6 +94,8 @@
|
||||
#ifndef GLOBAL_STRUCTURES_H
|
||||
#define GLOBAL_STRUCTURES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class TargetGroup;
|
||||
class Target;
|
||||
|
||||
@@ -155,35 +157,38 @@ struct ftpinfo {
|
||||
};
|
||||
|
||||
struct AVal {
|
||||
char *attribute;
|
||||
char value[256];
|
||||
struct AVal *next;
|
||||
const char *attribute;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
struct OS_Classification {
|
||||
char *OS_Vendor;
|
||||
char *OS_Family;
|
||||
char *OS_Generation; /* Can be NULL if unclassified */
|
||||
char *Device_Type;
|
||||
const char *OS_Vendor;
|
||||
const char *OS_Family;
|
||||
const char *OS_Generation; /* Can be NULL if unclassified */
|
||||
const char *Device_Type;
|
||||
};
|
||||
|
||||
#define MAX_OS_CLASSIFICATIONS_PER_FP 10
|
||||
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 */
|
||||
struct FingerTest {
|
||||
const char *name;
|
||||
struct AVal *results;
|
||||
struct FingerTest *next;
|
||||
} FingerPrint;
|
||||
std::vector<struct AVal> results;
|
||||
};
|
||||
|
||||
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
|
||||
database (nmap-os-db) */
|
||||
typedef struct FingerPrintDB {
|
||||
FingerPrint **prints;
|
||||
struct FingerPrintDB {
|
||||
FingerPrint *MatchPoints;
|
||||
} FingerPrintDB;
|
||||
std::vector<FingerPrint *> prints;
|
||||
|
||||
FingerPrintDB();
|
||||
~FingerPrintDB();
|
||||
};
|
||||
|
||||
struct timeout_info {
|
||||
int srtt; /* Smoothed rtt estimate (microseconds) */
|
||||
|
||||
4
nmap.cc
4
nmap.cc
@@ -1975,8 +1975,8 @@ void nmap_free_mem() {
|
||||
cp_free();
|
||||
free_dns_servers();
|
||||
free_etchosts();
|
||||
if(o.reference_FPs){
|
||||
free_fingerprint_file(o.reference_FPs);
|
||||
if (o.reference_FPs) {
|
||||
delete o.reference_FPs;
|
||||
o.reference_FPs = NULL;
|
||||
}
|
||||
AllProbes::service_scan_free();
|
||||
|
||||
463
osscan.cc
463
osscan.cc
@@ -100,6 +100,7 @@
|
||||
#include "nmap_error.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
@@ -112,27 +113,103 @@
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
extern NmapOps o;
|
||||
|
||||
static struct AVal *getattrbyname(struct AVal *AV, const char *name) {
|
||||
if (!AV) return NULL;
|
||||
do {
|
||||
if (!strcmp(AV->attribute, name))
|
||||
return AV;
|
||||
AV = AV->next;
|
||||
} while(AV);
|
||||
/* Store a string uniquely. The first time this function is called with a
|
||||
certain string, it allocates memory and stores a copy of the string in a
|
||||
static pool. Thereafter it will return a pointer to the saved string instead
|
||||
of allocating memory for an identical one. */
|
||||
const char *string_pool_insert(const char *s)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
do {
|
||||
if (!strcmp(FP->name, name))
|
||||
return FP->results;
|
||||
FP = FP->next;
|
||||
} while(FP);
|
||||
for (i = FP->tests.begin(); i != FP->tests.end(); i++) {
|
||||
if (strcmp(i->name, name) == 0)
|
||||
return &*i;
|
||||
};
|
||||
|
||||
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
|
||||
that extra info printed. If you pass 0 for verbose, you might as
|
||||
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_succeeded, int shortcut,
|
||||
int verbose, const char *testGroupName) {
|
||||
struct AVal *current_ref;
|
||||
struct AVal *current_fp;
|
||||
struct AVal *current_points;
|
||||
std::vector<struct AVal>::iterator current_ref;
|
||||
const struct AVal *current_fp;
|
||||
const struct AVal *current_points;
|
||||
unsigned int number, number1;
|
||||
unsigned int val;
|
||||
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 pointsThisTest = 1;
|
||||
|
||||
|
||||
for(current_ref = reference; current_ref; current_ref = current_ref->next) {
|
||||
for (current_ref = reference->results.begin();
|
||||
current_ref != reference->results.end();
|
||||
current_ref++) {
|
||||
current_fp = getattrbyname(fprint, current_ref->attribute);
|
||||
if (!current_fp) continue;
|
||||
/* 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. */
|
||||
double compare_fingerprints(FingerPrint *referenceFP, FingerPrint *observedFP,
|
||||
FingerPrint *MatchPoints, int verbose) {
|
||||
FingerPrint *currentReferenceTest;
|
||||
struct AVal *currentObservedTest;
|
||||
struct AVal *currentTestMatchPoints;
|
||||
std::vector<FingerTest>::iterator currentReferenceTest;
|
||||
FingerTest *currentObservedTest;
|
||||
FingerTest *currentTestMatchPoints;
|
||||
unsigned long num_subtests = 0, num_subtests_succeeded = 0;
|
||||
unsigned long new_subtests, new_subtests_succeeded;
|
||||
assert(referenceFP);
|
||||
assert(observedFP);
|
||||
|
||||
for(currentReferenceTest = referenceFP; currentReferenceTest;
|
||||
currentReferenceTest = currentReferenceTest->next) {
|
||||
for (currentReferenceTest = referenceFP->tests.begin();
|
||||
currentReferenceTest != referenceFP->tests.end();
|
||||
currentReferenceTest++) {
|
||||
currentObservedTest = gettestbyname(observedFP, currentReferenceTest->name);
|
||||
if (currentObservedTest) {
|
||||
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);
|
||||
} else currentTestMatchPoints = NULL;
|
||||
|
||||
AVal_match(currentReferenceTest->results, currentObservedTest, currentTestMatchPoints,
|
||||
AVal_match(&*currentReferenceTest, currentObservedTest, currentTestMatchPoints,
|
||||
&new_subtests, &new_subtests_succeeded, 0, verbose, currentReferenceTest->name);
|
||||
num_subtests += new_subtests;
|
||||
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. */
|
||||
void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
|
||||
FingerPrintDB *DB, double accuracy_threshold) {
|
||||
|
||||
int i;
|
||||
double FPR_entrance_requirement = accuracy_threshold; /* accuracy must be
|
||||
at least this big
|
||||
to be added to the
|
||||
list */
|
||||
FingerPrint **reference_FPs = DB->prints;
|
||||
FingerPrint *current_os;
|
||||
std::vector<FingerPrint *>::iterator current_os;
|
||||
double acc;
|
||||
int state;
|
||||
int skipfp;
|
||||
@@ -315,18 +391,17 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
|
||||
|
||||
FPR->overall_results = OSSCAN_SUCCESS;
|
||||
|
||||
for(i = 0; reference_FPs[i]; i++) {
|
||||
current_os = reference_FPs[i];
|
||||
for (current_os = DB->prints.begin(); current_os != DB->prints.end(); current_os++) {
|
||||
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); */
|
||||
if (acc >= FPR_entrance_requirement || acc == 1.0) {
|
||||
|
||||
state = 0;
|
||||
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) {
|
||||
skipfp = 1; /* Skip it -- a higher version is already in list */
|
||||
} else {
|
||||
@@ -370,7 +445,7 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
|
||||
/* OK, I insert the sucker into the next slot ... */
|
||||
tmp_acc = FPR->accuracy[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;
|
||||
state = 1;
|
||||
}
|
||||
@@ -396,21 +471,6 @@ void match_fingerprint(FingerPrint *FP, FingerPrintResults *FPR,
|
||||
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)
|
||||
{
|
||||
const char *s = "";
|
||||
@@ -482,50 +542,76 @@ static void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
|
||||
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
|
||||
null-terminated. Returns the number of bytes written, excluding the
|
||||
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 *end;
|
||||
size_t len;
|
||||
|
||||
if (AV == NULL) {
|
||||
if (n > 0)
|
||||
*s = '\0';
|
||||
if (n == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = s;
|
||||
end = s + n - 1;
|
||||
for ( ; AV != NULL; AV = AV->next) {
|
||||
if (p >= end)
|
||||
break;
|
||||
/* Put a separator in front of every attribute-value pair but the first. */
|
||||
if (p != s)
|
||||
*p++ = '%';
|
||||
len = MIN((ptrdiff_t) strlen(AV->attribute), end - p);
|
||||
memcpy(p, AV->attribute, len);
|
||||
|
||||
len = strlen(test->name);
|
||||
if (p + len > end)
|
||||
goto error;
|
||||
|
||||
memcpy(p, test->name, len);
|
||||
p += len;
|
||||
if (p >= end)
|
||||
break;
|
||||
if (p + 1 > end)
|
||||
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++ = '=';
|
||||
len = MIN((ptrdiff_t) strlen(AV->value), end - p);
|
||||
memcpy(p, AV->value, len);
|
||||
len = strlen(av->value);
|
||||
if (p + len > end)
|
||||
goto error;
|
||||
memcpy(p, av->value, len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
if (p + 1 > end)
|
||||
goto error;
|
||||
*p++ = ')';
|
||||
|
||||
*p = '\0';
|
||||
|
||||
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 count = 1;
|
||||
char *q = str, *p=str;
|
||||
struct AVal *AVs;
|
||||
if (!*str) return NULL;
|
||||
std::vector<struct AVal> AVs;
|
||||
|
||||
if (!*str)
|
||||
return std::vector<struct AVal>();
|
||||
|
||||
/* count the AVals */
|
||||
while((q = strchr(q, '%'))) {
|
||||
@@ -533,14 +619,16 @@ static struct AVal *str2AVal(char *str) {
|
||||
q++;
|
||||
}
|
||||
|
||||
AVs = (struct AVal *) safe_zalloc(count * sizeof(struct AVal));
|
||||
AVs.reserve(count);
|
||||
for(i=0; i < count; i++) {
|
||||
struct AVal av;
|
||||
|
||||
q = strchr(p, '=');
|
||||
if (!q) {
|
||||
fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
|
||||
}
|
||||
*q = '\0';
|
||||
AVs[i].attribute = strdup(p);
|
||||
av.attribute = string_pool_insert(p);
|
||||
p = q+1;
|
||||
if (i != count - 1) {
|
||||
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);
|
||||
}
|
||||
*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;
|
||||
AVs.push_back(av);
|
||||
}
|
||||
|
||||
return AVs;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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) {
|
||||
struct AVal *av_a, *av_b;
|
||||
static bool test_match_literal(const FingerTest *a, const FingerTest *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. */
|
||||
for (av_a = a; av_a != NULL; av_a = av_a->next) {
|
||||
av_b = getattrbyname(b, av_a->attribute);
|
||||
if (av_b == NULL || strcmp(av_a->value, av_b->value) != 0)
|
||||
for (i = a->results.begin(); i != a->results.end(); i++) {
|
||||
av = getattrbyname(b, i->attribute);
|
||||
if (av == NULL || strcmp(i->value, av->value) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
av_a = getattrbyname(a, av_b->attribute);
|
||||
if (av_a == NULL || strcmp(av_a->value, av_b->value) != 0)
|
||||
for (i = b->results.begin(); i != b->results.end(); i++) {
|
||||
av = getattrbyname(a, i->attribute);
|
||||
if (av == NULL || strcmp(i->value, av->value) != 0)
|
||||
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 */
|
||||
std::list<const FingerTest *> tests;
|
||||
std::list<const FingerTest *>::iterator iter;
|
||||
const FingerTest *ft;
|
||||
std::vector<FingerTest>::iterator ft;
|
||||
|
||||
if (numFPs <= 0)
|
||||
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. */
|
||||
for (i = 0; i < numFPs; i++) {
|
||||
for (ft = FPs[i]; ft != NULL; ft = ft->next)
|
||||
tests.push_back(ft);
|
||||
for (ft = FPs[i]->tests.begin(); ft != FPs[i]->tests.end(); ft++)
|
||||
tests.push_back(&*ft);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
next = tmp_i;
|
||||
next++;
|
||||
if (AVal_match_literal((*iter)->results, (*tmp_i)->results)) {
|
||||
if (test_match_literal(*iter, *tmp_i)) {
|
||||
/* This is a duplicate test. Remove it. */
|
||||
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. */
|
||||
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++) {
|
||||
if (strcmp((*iter)->name, ft->name) == 0
|
||||
&& AVal_match_literal((*iter)->results, ft->results)) {
|
||||
if (strcmp((*iter)->name, ft->name) == 0 && test_match_literal(*iter, &*ft)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iter == tests.end()) {
|
||||
char buf[200];
|
||||
AVal2str(ft->results, buf, sizeof(buf));
|
||||
fatal("The test %s(%s) was somehow lost in %s.\n", ft->name, buf, __func__);
|
||||
test2str(&*ft, buf, sizeof(buf));
|
||||
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. */
|
||||
for (iter = tests.begin(); iter != tests.end(); iter++) {
|
||||
size_t len;
|
||||
int len;
|
||||
|
||||
ft = *iter;
|
||||
len = MIN((ptrdiff_t) strlen(ft->name), (end - p));
|
||||
memcpy(p, ft->name, len);
|
||||
p += len;
|
||||
if (p >= end)
|
||||
len = test2str(*iter, p, end - p + 1);
|
||||
if (len == -1)
|
||||
break;
|
||||
*p++ = '(';
|
||||
len = AVal2str(ft->results, p, end - p + 1);
|
||||
p += len;
|
||||
if (p >= end)
|
||||
break;
|
||||
*p++ = ')';
|
||||
if (!wrapit) {
|
||||
if (p >= end)
|
||||
if (p + 1 > end)
|
||||
break;
|
||||
*p++ = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/* 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__);
|
||||
|
||||
*p = '\0';
|
||||
@@ -754,87 +835,52 @@ return str;
|
||||
}
|
||||
|
||||
const char *fp2ascii(FingerPrint *FP) {
|
||||
static char str[2048];
|
||||
FingerPrint *current;
|
||||
struct AVal *AV;
|
||||
char *p = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
static char str[2048];
|
||||
std::vector<FingerTest>::iterator iter;
|
||||
char *p = str;
|
||||
|
||||
if (!FP) return "(None)";
|
||||
if (!FP) return "(None)";
|
||||
|
||||
for(current = FP; current ; current = current->next) {
|
||||
Strncpy(p, current->name, sizeof(str) - (p-str));
|
||||
p += strlen(p);
|
||||
assert(p-str < (int) sizeof(str) - 30);
|
||||
*p++='(';
|
||||
for(AV = current->results; AV; AV = AV->next) {
|
||||
Strncpy(p, AV->attribute, sizeof(str) - (p-str));
|
||||
p += strlen(p);
|
||||
assert(p-str < (int) sizeof(str) - 30);
|
||||
*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++ = ')';
|
||||
for (iter = FP->tests.begin(); iter != FP->tests.end(); iter++) {
|
||||
int len;
|
||||
|
||||
len = test2str(&*iter, p, sizeof(str) - (p - str));
|
||||
if (len == -1)
|
||||
break;
|
||||
p += len;
|
||||
if (p + 1 > str + sizeof(str))
|
||||
break;
|
||||
*p++ = '\n';
|
||||
}
|
||||
*p = '\0';
|
||||
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;
|
||||
*p = '\0';
|
||||
|
||||
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;
|
||||
return str;
|
||||
}
|
||||
|
||||
/* 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
|
||||
current fingerprint. The function quits if there is a parse error */
|
||||
static void parse_classline(FingerPrint *FP, char *thisline, int lineno,
|
||||
int *classno) {
|
||||
static void parse_classline(FingerPrint *FP, char *thisline, int lineno) {
|
||||
const char *begin, *end;
|
||||
struct OS_Classification *os_class;
|
||||
struct OS_Classification os_class;
|
||||
|
||||
if (!thisline || strncmp(thisline, "Class ", 6) != 0)
|
||||
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. */
|
||||
begin = thisline + 6;
|
||||
end = strchr(begin, '|');
|
||||
if (end == NULL)
|
||||
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. */
|
||||
begin = end + 1;
|
||||
end = strchr(begin, '|');
|
||||
if (end == NULL)
|
||||
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. */
|
||||
begin = end + 1;
|
||||
@@ -846,17 +892,16 @@ static void parse_classline(FingerPrint *FP, char *thisline, int lineno,
|
||||
while (isspace((int) (unsigned char) *begin))
|
||||
begin++;
|
||||
if (begin < end)
|
||||
os_class->OS_Generation = substrstrip(begin, end);
|
||||
os_class.OS_Generation = string_pool_substr_strip(begin, end);
|
||||
else
|
||||
os_class->OS_Generation = NULL;
|
||||
os_class.OS_Generation = NULL;
|
||||
|
||||
/* And finally the device type. We look for '\0' instead of '|'. */
|
||||
begin = end + 1;
|
||||
end = strchr(begin, '\0');
|
||||
os_class->Device_Type = substrstrip(begin, end);
|
||||
os_class.Device_Type = string_pool_substr_strip(begin, end);
|
||||
|
||||
(*classno)++;
|
||||
FP->num_OS_Classifications++;
|
||||
FP->OS_class.push_back(os_class);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
FingerPrint *parse_single_fingerprint(char *fprint_orig) {
|
||||
int lineno = 0;
|
||||
int classno = 0; /* Number of Class lines dealt with so far */
|
||||
char *p, *q;
|
||||
char *thisline, *nextline;
|
||||
char *fprint = strdup(fprint_orig); /* Make a copy we can futz with */
|
||||
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;
|
||||
|
||||
@@ -914,15 +956,12 @@ FingerPrint *parse_single_fingerprint(char *fprint_orig) {
|
||||
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
|
||||
} else if (strncmp(thisline, "Class ", 6) == 0) {
|
||||
|
||||
parse_classline(FP, thisline, lineno, &classno);
|
||||
parse_classline(FP, thisline, lineno);
|
||||
|
||||
} else if ((q = strchr(thisline, '('))) {
|
||||
FingerTest test;
|
||||
*q = '\0';
|
||||
if(current->name) {
|
||||
current->next = (FingerPrint *) safe_zalloc(sizeof(FingerPrint));
|
||||
current = current->next;
|
||||
}
|
||||
current->name = strdup(thisline);
|
||||
test.name = string_pool_insert(thisline);
|
||||
p = q+1;
|
||||
*q = '(';
|
||||
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);
|
||||
}
|
||||
*q = '\0';
|
||||
current->results = str2AVal(p);
|
||||
test.results = str2AVal(p);
|
||||
FP->tests.push_back(test);
|
||||
} else {
|
||||
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 *DB = NULL;
|
||||
FingerPrint *current;
|
||||
FILE *fp;
|
||||
int max_records = 4096;
|
||||
char line[2048];
|
||||
int numrecords = 0;
|
||||
int lineno = 0;
|
||||
bool parsingMatchPoints = false;
|
||||
|
||||
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!!!! */
|
||||
|
||||
if (!DB) fatal("non-allocated DB passed to %s", __func__);
|
||||
|
||||
DB->prints = (FingerPrint **) safe_zalloc(sizeof(FingerPrint *) * max_records);
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp) fatal("Unable to open Nmap fingerprint file: %s", fname);
|
||||
|
||||
@@ -1033,13 +1024,13 @@ while(fgets(line, sizeof(line), fp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
current = (FingerPrint *) safe_zalloc(sizeof(FingerPrint));
|
||||
current = new FingerPrint;
|
||||
|
||||
if (parsingMatchPoints) {
|
||||
current->OS_name = NULL;
|
||||
DB->MatchPoints = current;
|
||||
} else {
|
||||
DB->prints[numrecords] = current;
|
||||
DB->prints.push_back(current);
|
||||
p = line + 12;
|
||||
while(*p && isspace((int) (unsigned char) *p)) p++;
|
||||
|
||||
@@ -1069,8 +1060,9 @@ while(fgets(line, sizeof(line), fp)) {
|
||||
if (!strncmp(line, "FingerPrint ",12)) {
|
||||
goto fparse;
|
||||
} else if (strncmp(line, "Class ", 6) == 0) {
|
||||
parse_classline(current, line, lineno, &classno);
|
||||
parse_classline(current, line, lineno);
|
||||
} else {
|
||||
FingerTest test;
|
||||
p = line;
|
||||
q = strchr(line, '(');
|
||||
if (!q) {
|
||||
@@ -1078,11 +1070,7 @@ while(fgets(line, sizeof(line), fp)) {
|
||||
goto top;
|
||||
}
|
||||
*q = '\0';
|
||||
if(current->name) {
|
||||
current->next = (FingerPrint *) safe_zalloc(sizeof(FingerPrint));
|
||||
current = current->next;
|
||||
}
|
||||
current->name = strdup(p);
|
||||
test.name = string_pool_insert(p);
|
||||
p = q+1;
|
||||
*q = '(';
|
||||
q = strchr(p, ')');
|
||||
@@ -1091,17 +1079,12 @@ while(fgets(line, sizeof(line), fp)) {
|
||||
goto top;
|
||||
}
|
||||
*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);
|
||||
DB->prints[numrecords] = NULL;
|
||||
return DB;
|
||||
}
|
||||
|
||||
|
||||
7
osscan.h
7
osscan.h
@@ -110,6 +110,13 @@
|
||||
/* moved to global_structures.h */
|
||||
|
||||
/********************** 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);
|
||||
|
||||
/* Parses a single fingerprint from the memory region given. If a
|
||||
|
||||
620
osscan2.cc
620
osscan2.cc
File diff suppressed because it is too large
Load Diff
@@ -1493,8 +1493,8 @@ void write_host_status(Target * currenths, int resolve_all) {
|
||||
that only unique entries are added. Also note that *numentries is
|
||||
incremented if the candidate is added. arrsize is the number of
|
||||
char * members that fit into arr */
|
||||
static int addtochararrayifnew(char *arr[], int *numentries, int arrsize,
|
||||
char *candidate) {
|
||||
static int addtochararrayifnew(const char *arr[], int *numentries, int arrsize,
|
||||
const char *candidate) {
|
||||
int i;
|
||||
|
||||
// First lets see if the member already exists
|
||||
@@ -1520,7 +1520,7 @@ static void printosclassificationoutput(const struct
|
||||
bool guess) {
|
||||
int classno, i, familyno;
|
||||
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]"
|
||||
double familyaccuracy[MAX_OS_CLASSMEMBERS]; // highest accuracy for this fullfamily
|
||||
char familygenerations[MAX_OS_CLASSMEMBERS][48]; // example: "4.X|5.X|6.X"
|
||||
|
||||
Reference in New Issue
Block a user