1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-07 13:11:28 +00:00

Short-circuit os fingerprint matching if accuracy cannot be achieved

This commit is contained in:
dmiller
2022-11-16 15:55:55 +00:00
parent f59d546c8f
commit d957ca1274
2 changed files with 23 additions and 7 deletions

View File

@@ -339,10 +339,13 @@ static int AVal_match(const FingerTest &reference, const FingerTest &fprint, con
accuracy (between 0 and 1) is returned). If MatchPoints is not NULL, it is accuracy (between 0 and 1) is returned). If MatchPoints is not NULL, it is
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(const FingerPrint *referenceFP, const FingerPrint *observedFP, double compare_fingerprints(const FingerPrint *referenceFP, const FingerPrint *observedFP,
const FingerPrintDef *MatchPoints, int verbose) { const FingerPrintDef *MatchPoints, int verbose,
double threshold) {
unsigned long num_subtests = 0, num_subtests_succeeded = 0; unsigned long num_subtests = 0, num_subtests_succeeded = 0;
assert(referenceFP); assert(referenceFP);
assert(observedFP); assert(observedFP);
// If we fall this far behind, we can't catch up
unsigned long max_mismatch = (1.0 - threshold) * referenceFP->match.numprints;
for (int i = 0; i < NUM_FPTESTS; i++) { for (int i = 0; i < NUM_FPTESTS; i++) {
const FingerTest &current_ref = referenceFP->tests[i]; const FingerTest &current_ref = referenceFP->tests[i];
@@ -355,6 +358,9 @@ double compare_fingerprints(const FingerPrint *referenceFP, const FingerPrint *o
&new_subtests, &new_subtests_succeeded, 0, verbose); &new_subtests, &new_subtests_succeeded, 0, verbose);
num_subtests += new_subtests; num_subtests += new_subtests;
num_subtests_succeeded += new_subtests_succeeded; num_subtests_succeeded += new_subtests_succeeded;
if (num_subtests - num_subtests_succeeded > max_mismatch) {
break;
}
} }
assert(num_subtests_succeeded <= num_subtests); assert(num_subtests_succeeded <= num_subtests);
@@ -394,7 +400,7 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR,
for (current_os = DB->prints.begin(); current_os != DB->prints.end(); current_os++) { for (current_os = DB->prints.begin(); current_os != DB->prints.end(); current_os++) {
skipfp = 0; skipfp = 0;
acc = compare_fingerprints(*current_os, &FP_copy, DB->MatchPoints, 0); acc = compare_fingerprints(*current_os, &FP_copy, DB->MatchPoints, 0, FPR_entrance_requirement);
if (acc >= FPR_entrance_requirement || acc == 1.0) { if (acc >= FPR_entrance_requirement || acc == 1.0) {
@@ -460,6 +466,7 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR,
/* Calculate the new min req. */ /* Calculate the new min req. */
if (FPR->num_matches == max_prints) { if (FPR->num_matches == max_prints) {
FPR_entrance_requirement = FPR->accuracy[max_prints - 1] + 0.00001; FPR_entrance_requirement = FPR->accuracy[max_prints - 1] + 0.00001;
FPR_entrance_requirement = MIN(FPR_entrance_requirement, 1.0);
} }
} }
} }
@@ -643,6 +650,15 @@ const char *FingerTest::getAVal(const char *attr) {
return results->at(idx); return results->at(idx);
} }
int FingerTest::getMaxPoints() const {
int points = 0;
for (size_t i = 0; i < def->numAttrs; i++) {
if ((*results)[i] != NULL)
points += def->Attrs[i].points;
}
return points;
}
/* This is a less-than relation predicate that establishes the preferred order /* This is a less-than relation predicate that establishes the preferred order
of tests when they are displayed. Returns true if and only if the test a of tests when they are displayed. Returns true if and only if the test a
should come before the test b. */ should come before the test b. */
@@ -1043,6 +1059,7 @@ fparse:
goto top; goto top;
} }
current->setTest(test); current->setTest(test);
current->match.numprints += test.getMaxPoints();
} }
} }
} }

View File

@@ -175,14 +175,12 @@ struct FingerMatch {
int line; /* For reference prints, the line # in nmap-os-db */ int line; /* For reference prints, the line # in nmap-os-db */
/* For IPv6 matches, the number of fingerprints that contributed to this /* For IPv6 matches, the number of fingerprints that contributed to this
* classification group */ * classification group */
/* For IPv4 fingerprints, the number of points possible */
unsigned short numprints; unsigned short numprints;
const char *OS_name; const char *OS_name;
std::vector<OS_Classification> OS_class; std::vector<OS_Classification> OS_class;
FingerMatch() { FingerMatch() : line(-1), numprints(0), OS_name(NULL) {}
line = -1;
OS_name = NULL;
}
}; };
struct FingerPrintDB; struct FingerPrintDB;
@@ -210,6 +208,7 @@ struct FingerTest {
const char *getAVal(const char *attr); const char *getAVal(const char *attr);
const char *getAValName(u8 index) const; const char *getAValName(u8 index) const;
const char *getTestName() const { return def->name.str; } const char *getTestName() const { return def->name.str; }
int getMaxPoints() const;
}; };
struct FingerPrint { struct FingerPrint {
@@ -256,7 +255,7 @@ void free_fingerprint_file(FingerPrintDB *DB);
accuracy (between 0 and 1) is returned). MatchPoints is accuracy (between 0 and 1) is returned). MatchPoints is
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(const FingerPrint *referenceFP, const FingerPrint *observedFP, double compare_fingerprints(const FingerPrint *referenceFP, const FingerPrint *observedFP,
const FingerPrintDef *MatchPoints, int verbose); const FingerPrintDef *MatchPoints, int verbose, double threshold);
/* Takes a fingerprint and looks for matches inside the passed in /* Takes a fingerprint and looks for matches inside the passed in
reference fingerprint DB. The results are stored in in FPR (which reference fingerprint DB. The results are stored in in FPR (which