diff --git a/osscan.cc b/osscan.cc index a3f505b77..ae4d57b66 100644 --- a/osscan.cc +++ b/osscan.cc @@ -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 a special "fingerprints" which tells how many points each test is worth. */ 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; assert(referenceFP); 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++) { const FingerTest ¤t_ref = referenceFP->tests[i]; @@ -355,6 +358,9 @@ double compare_fingerprints(const FingerPrint *referenceFP, const FingerPrint *o &new_subtests, &new_subtests_succeeded, 0, verbose); num_subtests += new_subtests; num_subtests_succeeded += new_subtests_succeeded; + if (num_subtests - num_subtests_succeeded > max_mismatch) { + break; + } } 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++) { 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) { @@ -460,6 +466,7 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR, /* Calculate the new min req. */ if (FPR->num_matches == max_prints) { 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); } +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 of tests when they are displayed. Returns true if and only if the test a should come before the test b. */ @@ -1043,6 +1059,7 @@ fparse: goto top; } current->setTest(test); + current->match.numprints += test.getMaxPoints(); } } } diff --git a/osscan.h b/osscan.h index bc462567b..96afcb7e8 100644 --- a/osscan.h +++ b/osscan.h @@ -175,14 +175,12 @@ struct FingerMatch { int line; /* For reference prints, the line # in nmap-os-db */ /* For IPv6 matches, the number of fingerprints that contributed to this * classification group */ + /* For IPv4 fingerprints, the number of points possible */ unsigned short numprints; const char *OS_name; std::vector OS_class; - FingerMatch() { - line = -1; - OS_name = NULL; - } + FingerMatch() : line(-1), numprints(0), OS_name(NULL) {} }; struct FingerPrintDB; @@ -210,6 +208,7 @@ struct FingerTest { const char *getAVal(const char *attr); const char *getAValName(u8 index) const; const char *getTestName() const { return def->name.str; } + int getMaxPoints() const; }; struct FingerPrint { @@ -256,7 +255,7 @@ void free_fingerprint_file(FingerPrintDB *DB); accuracy (between 0 and 1) is returned). MatchPoints is a special "fingerprints" which tells how many points each test is worth. */ 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 reference fingerprint DB. The results are stored in in FPR (which