mirror of
https://github.com/nmap/nmap.git
synced 2025-12-15 04:09:01 +00:00
Optimizations for IPv4 OS scan
Since the number, names, and preferred order of OS detection tests are known, we can use fixed indices to put each test/value type in a predictable location. Previously, we would insert the tests in an arbitrary order, sort them, and then use strcmp() in each comparison to ensure the sort order holds and any missing tests are skipped over. Keeping test names in one location (MatchPoints) saves memory and keeps the string pool small, which improves performance by reducing lookups and making existing lookups faster. Using a dedicated class (FingerPrintDef) for MatchPoints avoids calling strtol() to obtain the points value for every comparison.
This commit is contained in:
555
osscan.cc
555
osscan.cc
@@ -78,6 +78,88 @@
|
|||||||
|
|
||||||
extern NmapOps o;
|
extern NmapOps o;
|
||||||
|
|
||||||
|
template<u8 _MaxStrLen> void ShortStr<_MaxStrLen>::setStr(const char *in) {
|
||||||
|
const char *end = in;
|
||||||
|
while (end - in < _MaxStrLen && *++end);
|
||||||
|
setStr(in, end);
|
||||||
|
trunc = trunc || *end;
|
||||||
|
}
|
||||||
|
template<u8 _MaxStrLen> void ShortStr<_MaxStrLen>::setStr(const char *in, const char *end) {
|
||||||
|
assert(end > in && in != NULL);
|
||||||
|
int len = end - in;
|
||||||
|
len = MIN(len, _MaxStrLen);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (; i < len; i++) {
|
||||||
|
char c = in[i];
|
||||||
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')) {
|
||||||
|
str[i] = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str[i] = '\0';
|
||||||
|
trunc = i < (end - in);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *FingerPrintDef::test_attrs[NUM_FPTESTS][FP_MAX_TEST_ATTRS] = {
|
||||||
|
/* SEQ */ {"SP", "GCD", "ISR", "TI", "CI", "II", "SS", "TS"},
|
||||||
|
/* OPS */ {"O1", "O2", "O3", "O4", "O5", "O6"},
|
||||||
|
/* WIN */ {"W1", "W2", "W3", "W4", "W5", "W6"},
|
||||||
|
/* ECN */ {"R", "DF", "T", "TG", "W", "O", "CC", "Q"},
|
||||||
|
/* T1 */ {"R", "DF", "T", "TG", "S", "A", "F", "RD", "Q"},
|
||||||
|
/* T2 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* T3 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* T4 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* T5 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* T6 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* T7 */ {"R", "DF", "T", "TG", "W", "S", "A", "F", "O", "RD", "Q"},
|
||||||
|
/* U1 */ {"R", "DF", "T", "TG", "IPL", "UN", "RIPL", "RID", "RIPCK", "RUCK", "RUD"},
|
||||||
|
/* IE */ {"R", "DFI", "T", "TG", "CD"}
|
||||||
|
};
|
||||||
|
|
||||||
|
FingerPrintDef::FingerPrintDef() {
|
||||||
|
TestDefs.reserve(NUM_FPTESTS);
|
||||||
|
int i = 0;
|
||||||
|
FPstr name;
|
||||||
|
#define ADD_TEST_DEF(_Name) \
|
||||||
|
i = ID2INT(_Name); \
|
||||||
|
name = FPstr(#_Name); \
|
||||||
|
TestDefs.push_back(FingerTestDef(name, test_attrs[i])); \
|
||||||
|
assert(TestDefs[i].name == name); \
|
||||||
|
TestIdx.insert(std::make_pair(name, _Name));
|
||||||
|
|
||||||
|
ADD_TEST_DEF(SEQ);
|
||||||
|
ADD_TEST_DEF(OPS);
|
||||||
|
ADD_TEST_DEF(WIN);
|
||||||
|
ADD_TEST_DEF(ECN);
|
||||||
|
ADD_TEST_DEF(T1);
|
||||||
|
ADD_TEST_DEF(T2);
|
||||||
|
ADD_TEST_DEF(T3);
|
||||||
|
ADD_TEST_DEF(T4);
|
||||||
|
ADD_TEST_DEF(T5);
|
||||||
|
ADD_TEST_DEF(T6);
|
||||||
|
ADD_TEST_DEF(T7);
|
||||||
|
ADD_TEST_DEF(U1);
|
||||||
|
ADD_TEST_DEF(IE);
|
||||||
|
|
||||||
|
assert(FingerPrintDef::INVALID == INT2ID(NUM_FPTESTS));
|
||||||
|
assert(TestDefs.size() == NUM_FPTESTS);
|
||||||
|
assert(TestIdx.size() == NUM_FPTESTS);
|
||||||
|
};
|
||||||
|
|
||||||
|
FingerTestDef::FingerTestDef(const FPstr &n, const char *a[])
|
||||||
|
: name(n), numAttrs(0) {
|
||||||
|
hasR = (0 == strcmp(a[0], "R"));
|
||||||
|
Attrs.reserve(FP_MAX_TEST_ATTRS);
|
||||||
|
while (numAttrs < FP_MAX_TEST_ATTRS && a[numAttrs] != NULL) {
|
||||||
|
Attr attr(a[numAttrs]);
|
||||||
|
Attrs.push_back(attr);
|
||||||
|
AttrIdx.insert(std::make_pair(attr.name, numAttrs));
|
||||||
|
numAttrs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FingerPrintDB::FingerPrintDB() : MatchPoints(NULL) {
|
FingerPrintDB::FingerPrintDB() : MatchPoints(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +167,6 @@ FingerPrintDB::~FingerPrintDB() {
|
|||||||
std::vector<FingerPrint *>::iterator current;
|
std::vector<FingerPrint *>::iterator current;
|
||||||
|
|
||||||
if (MatchPoints != NULL) {
|
if (MatchPoints != NULL) {
|
||||||
MatchPoints->erase();
|
|
||||||
delete MatchPoints;
|
delete MatchPoints;
|
||||||
}
|
}
|
||||||
for (current = prints.begin(); current != prints.end(); current++) {
|
for (current = prints.begin(); current != prints.end(); current++) {
|
||||||
@@ -94,9 +175,35 @@ FingerPrintDB::~FingerPrintDB() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FingerTest::FingerTest(bool allocResults) : name(NULL), results(NULL) {
|
bool FingerPrintDef::parseTestStr(const char *str, const char *end) {
|
||||||
if (allocResults)
|
const char *p = str;
|
||||||
this->results = new std::vector<struct AVal>;
|
const char *q = strchr_p(p, end, '(');
|
||||||
|
if (!q)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::map<FPstr, TestID>::iterator t_i = TestIdx.find(FPstr(p, q));
|
||||||
|
if (t_i == TestIdx.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FingerTestDef &test = getTestDef(t_i->second);
|
||||||
|
p = q + 1;
|
||||||
|
while ((q = strchr_p(p, end, '='))) {
|
||||||
|
std::map<FPstr, u8>::iterator a_i = test.AttrIdx.find(FPstr(p, q));
|
||||||
|
if (a_i == test.AttrIdx.end())
|
||||||
|
return false;
|
||||||
|
Attr &attr = test.Attrs[a_i->second];
|
||||||
|
|
||||||
|
p = q + 1;
|
||||||
|
errno = 0;
|
||||||
|
attr.points = strtol(p, NULL, 10);
|
||||||
|
if (errno != 0 || attr.points <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (NULL == (p = strchr_p(q, end, '%')))
|
||||||
|
break;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FingerTest::erase() {
|
void FingerTest::erase() {
|
||||||
@@ -106,18 +213,9 @@ void FingerTest::erase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FingerPrint::sort() {
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < tests.size(); i++)
|
|
||||||
std::stable_sort(tests[i].results->begin(), tests[i].results->end());
|
|
||||||
std::stable_sort(tests.begin(), tests.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FingerPrint::erase() {
|
void FingerPrint::erase() {
|
||||||
for (std::vector<FingerTest>::iterator t = this->tests.begin();
|
for (int i=0; i < NUM_FPTESTS; i++) {
|
||||||
t != this->tests.end(); t++) {
|
tests[i].erase();
|
||||||
t->erase();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,69 +284,45 @@ static bool expr_match(const char *val, const char *expr) {
|
|||||||
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(const FingerTest *reference, const FingerTest *fprint, const FingerTest *points,
|
static int AVal_match(const FingerTest &reference, const FingerTest &fprint, const FingerTestDef &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) {
|
int verbose) {
|
||||||
std::vector<struct AVal>::const_iterator current_ref, prev_ref;
|
|
||||||
std::vector<struct AVal>::const_iterator current_fp, prev_fp;
|
|
||||||
std::vector<struct AVal>::const_iterator current_points;
|
|
||||||
int subtests = 0, subtests_succeeded=0;
|
int subtests = 0, subtests_succeeded=0;
|
||||||
int pointsThisTest = 1;
|
if (!reference.results || !fprint.results)
|
||||||
char *endptr;
|
return 0;
|
||||||
|
|
||||||
/* We rely on AVals being sorted by attribute. */
|
const std::vector<Attr> &pointsV = points.Attrs;
|
||||||
prev_ref = reference->results->end();
|
|
||||||
prev_fp = fprint->results->end();
|
|
||||||
current_ref = reference->results->begin();
|
|
||||||
current_fp = fprint->results->begin();
|
|
||||||
current_points = points->results->begin();
|
|
||||||
while (current_ref != reference->results->end()
|
|
||||||
&& current_fp != fprint->results->end()) {
|
|
||||||
int d;
|
|
||||||
|
|
||||||
/* Check for sortedness. */
|
const std::vector<const char *> &refV = *reference.results;
|
||||||
if (prev_ref != reference->results->end())
|
assert(refV.size() == points.numAttrs);
|
||||||
assert(*prev_ref < *current_ref);
|
|
||||||
if (prev_fp != fprint->results->end())
|
|
||||||
assert(*prev_fp < *current_fp);
|
|
||||||
|
|
||||||
d = strcmp(current_ref->attribute, current_fp->attribute);
|
const std::vector<const char *> &fpV = *fprint.results;
|
||||||
if (d == 0) {
|
assert(refV.size() == points.numAttrs);
|
||||||
for (; current_points != points->results->end(); current_points++) {
|
|
||||||
if (strcmp(current_ref->attribute, current_points->attribute) == 0)
|
for (size_t i = 0; i < points.numAttrs; i++) {
|
||||||
break;
|
const char *current_ref = refV[i];
|
||||||
|
const char *current_fp = fpV[i];
|
||||||
|
const Attr &aDef = pointsV[i];
|
||||||
|
if (current_ref == NULL || current_fp == NULL)
|
||||||
|
continue;
|
||||||
|
int pointsThisTest = aDef.points;
|
||||||
|
if (pointsThisTest < 0)
|
||||||
|
fatal("%s: Got bogus point amount (%d) for test %s.%s", __func__, pointsThisTest, points.name.str, aDef.name.str);
|
||||||
|
subtests += pointsThisTest;
|
||||||
|
|
||||||
|
if (expr_match(current_fp, current_ref)) {
|
||||||
|
subtests_succeeded += pointsThisTest;
|
||||||
|
} else {
|
||||||
|
if (shortcut) {
|
||||||
|
if (num_subtests)
|
||||||
|
*num_subtests += subtests;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (current_points == points->results->end())
|
if (verbose)
|
||||||
fatal("%s: Failed to find point amount for test %s.%s", __func__, reference->name ? reference->name : "", current_ref->attribute);
|
log_write(LOG_PLAIN, "%s.%s: \"%s\" NOMATCH \"%s\" (%d %s)\n", points.name.str,
|
||||||
errno = 0;
|
aDef.name.str, current_fp,
|
||||||
pointsThisTest = strtol(current_points->value, &endptr, 10);
|
current_ref, pointsThisTest, (pointsThisTest == 1) ? "point" : "points");
|
||||||
if (errno != 0 || *endptr != '\0' || pointsThisTest < 0)
|
|
||||||
fatal("%s: Got bogus point amount (%s) for test %s.%s", __func__, current_points->value, reference->name ? reference->name : "", current_ref->attribute);
|
|
||||||
subtests += pointsThisTest;
|
|
||||||
|
|
||||||
if (expr_match(current_fp->value, current_ref->value)) {
|
|
||||||
subtests_succeeded += pointsThisTest;
|
|
||||||
} else {
|
|
||||||
if (shortcut) {
|
|
||||||
if (num_subtests)
|
|
||||||
*num_subtests += subtests;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (verbose)
|
|
||||||
log_write(LOG_PLAIN, "%s.%s: \"%s\" NOMATCH \"%s\" (%d %s)\n", reference->name,
|
|
||||||
current_ref->attribute, current_fp->value,
|
|
||||||
current_ref->value, pointsThisTest, (pointsThisTest == 1) ? "point" : "points");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d <= 0) {
|
|
||||||
prev_ref = current_ref;
|
|
||||||
current_ref++;
|
|
||||||
}
|
|
||||||
if (d >= 0) {
|
|
||||||
prev_fp = current_fp;
|
|
||||||
current_fp++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (num_subtests)
|
if (num_subtests)
|
||||||
@@ -265,55 +339,22 @@ 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 FingerPrint *MatchPoints, int verbose) {
|
const FingerPrintDef *MatchPoints, int verbose) {
|
||||||
std::vector<FingerTest>::const_iterator current_ref, prev_ref;
|
|
||||||
std::vector<FingerTest>::const_iterator current_fp, prev_fp;
|
|
||||||
std::vector<FingerTest>::const_iterator current_points;
|
|
||||||
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;
|
|
||||||
assert(referenceFP);
|
assert(referenceFP);
|
||||||
assert(observedFP);
|
assert(observedFP);
|
||||||
|
|
||||||
/* We rely on tests being sorted by name. */
|
for (int i = 0; i < NUM_FPTESTS; i++) {
|
||||||
prev_ref = referenceFP->tests.end();
|
const FingerTest ¤t_ref = referenceFP->tests[i];
|
||||||
prev_fp = observedFP->tests.end();
|
const FingerTest ¤t_fp = observedFP->tests[i];
|
||||||
current_ref = referenceFP->tests.begin();
|
const FingerTestDef &points = MatchPoints->getTestDef(INT2ID(i));
|
||||||
current_fp = observedFP->tests.begin();
|
|
||||||
current_points = MatchPoints->tests.begin();
|
|
||||||
while (current_ref != referenceFP->tests.end()
|
|
||||||
&& current_fp != observedFP->tests.end()) {
|
|
||||||
int d;
|
|
||||||
|
|
||||||
/* Check for sortedness. */
|
unsigned long new_subtests = 0, new_subtests_succeeded = 0;
|
||||||
if (prev_ref != referenceFP->tests.end())
|
|
||||||
assert(strcmp(prev_ref->name, current_ref->name) < 0);
|
|
||||||
if (prev_fp != observedFP->tests.end())
|
|
||||||
assert(strcmp(prev_fp->name, current_fp->name) < 0);
|
|
||||||
|
|
||||||
d = strcmp(current_ref->name, current_fp->name);
|
AVal_match(current_ref, current_fp, points,
|
||||||
if (d == 0) {
|
&new_subtests, &new_subtests_succeeded, 0, verbose);
|
||||||
new_subtests = new_subtests_succeeded = 0;
|
num_subtests += new_subtests;
|
||||||
for (; current_points != MatchPoints->tests.end(); current_points++) {
|
num_subtests_succeeded += new_subtests_succeeded;
|
||||||
if (strcmp(current_ref->name, current_points->name) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (current_points == MatchPoints->tests.end())
|
|
||||||
fatal("%s: Failed to locate test %s in MatchPoints directive of fingerprint file", __func__, current_ref->name);
|
|
||||||
|
|
||||||
AVal_match(&*current_ref, &*current_fp, &*current_points,
|
|
||||||
&new_subtests, &new_subtests_succeeded, 0, verbose);
|
|
||||||
num_subtests += new_subtests;
|
|
||||||
num_subtests_succeeded += new_subtests_succeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d <= 0) {
|
|
||||||
prev_ref = current_ref;
|
|
||||||
current_ref++;
|
|
||||||
}
|
|
||||||
if (d >= 0) {
|
|
||||||
prev_fp = current_fp;
|
|
||||||
current_fp++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(num_subtests_succeeded <= num_subtests);
|
assert(num_subtests_succeeded <= num_subtests);
|
||||||
@@ -347,7 +388,6 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR,
|
|||||||
assert(accuracy_threshold >= 0 && accuracy_threshold <= 1);
|
assert(accuracy_threshold >= 0 && accuracy_threshold <= 1);
|
||||||
|
|
||||||
FP_copy = *FP;
|
FP_copy = *FP;
|
||||||
FP_copy.sort();
|
|
||||||
|
|
||||||
FPR->overall_results = OSSCAN_SUCCESS;
|
FPR->overall_results = OSSCAN_SUCCESS;
|
||||||
|
|
||||||
@@ -356,7 +396,6 @@ void match_fingerprint(const FingerPrint *FP, FingerPrintResultsIPv4 *FPR,
|
|||||||
|
|
||||||
acc = compare_fingerprints(*current_os, &FP_copy, DB->MatchPoints, 0);
|
acc = compare_fingerprints(*current_os, &FP_copy, 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) {
|
if (acc >= FPR_entrance_requirement || acc == 1.0) {
|
||||||
|
|
||||||
state = 0;
|
state = 0;
|
||||||
@@ -510,10 +549,8 @@ void WriteSInfo(char *ostr, int ostrlen, bool isGoodFP,
|
|||||||
null-terminated. Returns the number of bytes written, excluding the
|
null-terminated. Returns the number of bytes written, excluding the
|
||||||
terminator. */
|
terminator. */
|
||||||
static int test2str(const FingerTest *test, char *s, const size_t n) {
|
static int test2str(const FingerTest *test, char *s, const size_t n) {
|
||||||
std::vector<struct AVal>::const_iterator av;
|
|
||||||
char *p;
|
char *p;
|
||||||
char *end;
|
char *end;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -521,40 +558,29 @@ static int test2str(const FingerTest *test, char *s, const size_t n) {
|
|||||||
p = s;
|
p = s;
|
||||||
end = s + n - 1;
|
end = s + n - 1;
|
||||||
|
|
||||||
len = strlen(test->name);
|
std::vector<const char *> &results = *test->results;
|
||||||
if (p + len > end)
|
p += Snprintf(p, n, "%s(", test->getTestName());
|
||||||
|
if (p > end)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
memcpy(p, test->name, len);
|
assert(results.size() == test->def->numAttrs);
|
||||||
p += len;
|
for (u8 i = 0; i < results.size(); i++) {
|
||||||
if (p + 1 > end)
|
if (results[i] == NULL)
|
||||||
goto error;
|
continue;
|
||||||
*p++ = '(';
|
p += Snprintf(p, end - p, "%s=%s%%", test->getAValName(i), results[i]);
|
||||||
|
if (p > end)
|
||||||
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;
|
goto error;
|
||||||
memcpy(p, av->attribute, len);
|
|
||||||
p += len;
|
|
||||||
if (p + 1 > end)
|
|
||||||
goto error;
|
|
||||||
*p++ = '=';
|
|
||||||
len = strlen(av->value);
|
|
||||||
if (p + len > end)
|
|
||||||
goto error;
|
|
||||||
memcpy(p, av->value, len);
|
|
||||||
p += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p + 1 > end)
|
// overwrite last '%' with ')'
|
||||||
|
if (*(p - 1) == '%')
|
||||||
|
*(p - 1) = ')';
|
||||||
|
// if there were no results and there is space for it, close parenthesis
|
||||||
|
else if (*(p - 1) == '(' && p < end)
|
||||||
|
*p++ = ')';
|
||||||
|
// otherwise, something went wrong.
|
||||||
|
else
|
||||||
goto error;
|
goto error;
|
||||||
*p++ = ')';
|
|
||||||
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
@@ -566,101 +592,94 @@ error:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<struct AVal> *str2AVal(const char *str, const char *end) {
|
bool FingerTest::str2AVal(const char *str, const char *end) {
|
||||||
int i = 1;
|
assert(results);
|
||||||
int count = 1;
|
assert(def);
|
||||||
const char *q = str, *p=str;
|
const char *q = str, *p=str;
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
if (!def->hasR && 0 == strncmp("R=N", str, end - str)) {
|
||||||
|
return true;
|
||||||
if (!*str || str == end)
|
|
||||||
return AVs;
|
|
||||||
|
|
||||||
/* count the AVals */
|
|
||||||
while ((q = strchr_p(q, end, '%'))) {
|
|
||||||
count++;
|
|
||||||
q++;
|
|
||||||
}
|
}
|
||||||
|
u8 count = def->numAttrs;
|
||||||
|
std::vector<const char *> &AVs = *results;
|
||||||
|
|
||||||
AVs->reserve(count);
|
for (u8 i = 0; i < count && p < end; i++) {
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
struct AVal av;
|
|
||||||
|
|
||||||
q = strchr_p(p, end, '=');
|
q = strchr_p(p, end, '=');
|
||||||
if (!q) {
|
if (!q) {
|
||||||
fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
|
error("Parse error with AVal string (%s) in nmap-os-db file", str);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::map<FPstr, u8>::const_iterator idx = def->AttrIdx.find(FPstr(p, q));
|
||||||
|
if (idx == def->AttrIdx.end() || AVs[idx->second] != NULL) {
|
||||||
|
error("Parse error with AVal string (%s) in nmap-os-db file", str);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
av.attribute = string_pool_substr(p, q);
|
|
||||||
p = q+1;
|
p = q+1;
|
||||||
if (i < count - 1) {
|
q = strchr_p(p, end, '%');
|
||||||
q = strchr_p(p, end, '%');
|
if (!q) {
|
||||||
if (!q) {
|
q = end;
|
||||||
fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
|
|
||||||
}
|
|
||||||
av.value = string_pool_substr(p, q);
|
|
||||||
} else {
|
|
||||||
av.value = string_pool_substr(p, end);
|
|
||||||
}
|
}
|
||||||
|
if (p != q) // empty? use NULL
|
||||||
|
AVs[idx->second] = string_pool_substr(p, q);
|
||||||
p = q + 1;
|
p = q + 1;
|
||||||
AVs->push_back(av);
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return AVs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare two AVal chains literally, without evaluating the value of either one
|
void FingerTest::setAVal(const char *attr, const char *value) {
|
||||||
as an expression. This is used by mergeFPs. Unlike with AVal_match, it is
|
u8 idx = def->AttrIdx.at(attr);
|
||||||
always the case that test_match_literal(a, b) == test_match_literal(b, a). */
|
assert(idx < results->size());
|
||||||
static bool test_match_literal(const FingerTest *a, const FingerTest *b) {
|
(*results)[idx] = value;
|
||||||
std::vector<struct AVal>::const_iterator ia, ib;
|
}
|
||||||
|
|
||||||
for (ia = a->results->begin(), ib = b->results->begin();
|
const char *FingerTest::getAValName(u8 index) const {
|
||||||
ia != a->results->end() && ib != b->results->end();
|
return def->Attrs.at(index).name;
|
||||||
ia++, ib++) {
|
}
|
||||||
if (strcmp(ia->attribute, ib->attribute) != 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ia != a->results->end() || ib != b->results->end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
const char *FingerTest::getAVal(const char *attr) {
|
||||||
|
if (!results)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
u8 idx = def->AttrIdx.at(attr);
|
||||||
|
return results->at(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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. */
|
||||||
static bool FingerTest_lessthan(const FingerTest* a, const FingerTest* b) {
|
struct FingerTestCmp {
|
||||||
/* This defines the order in which test lines should appear. */
|
bool operator()(const FingerTest* a, const FingerTest* b) {
|
||||||
const char *TEST_ORDER[] = {
|
if (a->id != b->id)
|
||||||
"SEQ", "OPS", "WIN", "ECN",
|
return a->id < b->id;
|
||||||
"T1", "T2", "T3", "T4", "T5", "T6", "T7",
|
if (a->results == NULL) {
|
||||||
"U1", "IE"
|
return b->results != NULL;
|
||||||
};
|
}
|
||||||
unsigned int i;
|
else if (b->results == NULL) {
|
||||||
int ia, ib;
|
return false;
|
||||||
|
}
|
||||||
|
const std::vector<const char *> &av_a = *a->results;
|
||||||
|
size_t numtests = av_a.size();
|
||||||
|
const std::vector<const char *> &av_b = *b->results;
|
||||||
|
assert(av_b.size() == numtests);
|
||||||
|
|
||||||
/* The indices at which the test names were found in the list. -1 means "not
|
for (size_t i = 0; i < numtests; i++) {
|
||||||
found." */
|
if (av_a[i] == NULL) {
|
||||||
ia = -1;
|
if (av_b[i] == NULL)
|
||||||
ib = -1;
|
continue;
|
||||||
/* Look up the test names in the list. */
|
else
|
||||||
for (i = 0; i < sizeof(TEST_ORDER) / sizeof(*TEST_ORDER); i++) {
|
return true;
|
||||||
if (ia == -1 && strcmp(a->name, TEST_ORDER[i]) == 0)
|
}
|
||||||
ia = i;
|
else if (av_b[i] == NULL) {
|
||||||
if (ib == -1 && strcmp(b->name, TEST_ORDER[i]) == 0)
|
return false;
|
||||||
ib = i;
|
}
|
||||||
/* Once we've found both tests we can stop searching. */
|
int cmp = strcmp(av_a[i], av_b[i]);
|
||||||
if (ia != -1 && ib != -1)
|
if (cmp == 0)
|
||||||
break;
|
continue;
|
||||||
|
else
|
||||||
|
return cmp < 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
/* If a test name was not found, it probably indicates an error in another
|
};
|
||||||
part of the code. */
|
|
||||||
if (ia == -1)
|
|
||||||
fatal("%s received an unknown test name \"%s\".\n", __func__, a->name);
|
|
||||||
if (ib == -1)
|
|
||||||
fatal("%s received an unknown test name \"%s\".\n", __func__, b->name);
|
|
||||||
|
|
||||||
return ia < ib;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Merges the tests from several fingerprints into a character string
|
/* Merges the tests from several fingerprints into a character string
|
||||||
representation. Tests that are identical between more than one fingerprint
|
representation. Tests that are identical between more than one fingerprint
|
||||||
@@ -675,58 +694,22 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
|
|||||||
static char wrapstr[10240];
|
static char wrapstr[10240];
|
||||||
|
|
||||||
char *p;
|
char *p;
|
||||||
int i;
|
|
||||||
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::set<const FingerTest *, FingerTestCmp> tests;
|
||||||
std::list<const FingerTest *>::iterator iter;
|
std::set<const FingerTest *, FingerTestCmp>::iterator iter;
|
||||||
std::vector<FingerTest>::iterator ft;
|
|
||||||
|
|
||||||
if (numFPs <= 0)
|
if (numFPs <= 0)
|
||||||
return "(None)";
|
return "(None)";
|
||||||
else if (numFPs > 32)
|
else if (numFPs > 32)
|
||||||
return "(Too many)";
|
return "(Too many)";
|
||||||
|
|
||||||
/* Copy the tests from each fingerprint into a flat list. */
|
|
||||||
for (i = 0; i < numFPs; i++) {
|
|
||||||
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
|
/* Put the tests in the proper order and ensure that tests with identical
|
||||||
names are contiguous. */
|
names are contiguous. */
|
||||||
tests.sort(FingerTest_lessthan);
|
for (int i = 0; i < numFPs; i++) {
|
||||||
|
for (int j = 0; j < NUM_FPTESTS; j++) {
|
||||||
/* Delete duplicate tests to ensure that all the tests are unique. One test is
|
const FingerTest &ft = FPs[i]->tests[j];
|
||||||
a duplicate of the other if it has the same name as the first and the two
|
if (ft.id != FingerPrintDef::INVALID)
|
||||||
results lists match. */
|
tests.insert(&ft);
|
||||||
for (iter = tests.begin(); iter != tests.end(); iter++) {
|
|
||||||
std::list<const FingerTest *>::iterator tmp_i, next;
|
|
||||||
tmp_i = iter;
|
|
||||||
tmp_i++;
|
|
||||||
while (tmp_i != tests.end() && strcmp((*iter)->name, (*tmp_i)->name) == 0) {
|
|
||||||
next = tmp_i;
|
|
||||||
next++;
|
|
||||||
if (test_match_literal(*iter, *tmp_i)) {
|
|
||||||
/* This is a duplicate test. Remove it. */
|
|
||||||
tests.erase(tmp_i);
|
|
||||||
}
|
|
||||||
tmp_i = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A safety check to make sure that no tests were lost in merging. */
|
|
||||||
for (i = 0; i < numFPs; i++) {
|
|
||||||
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 && test_match_literal(*iter, &*ft)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (iter == tests.end()) {
|
|
||||||
char buf[200];
|
|
||||||
test2str(&*ft, buf, sizeof(buf));
|
|
||||||
fatal("The test %s was somehow lost in %s.\n", buf, __func__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,16 +777,18 @@ const char *mergeFPs(FingerPrint *FPs[], int numFPs, bool isGoodFP,
|
|||||||
|
|
||||||
const char *fp2ascii(const FingerPrint *FP) {
|
const char *fp2ascii(const FingerPrint *FP) {
|
||||||
static char str[2048];
|
static char str[2048];
|
||||||
std::vector<FingerTest>::const_iterator iter;
|
|
||||||
char *p = str;
|
char *p = str;
|
||||||
|
|
||||||
if (!FP)
|
if (!FP)
|
||||||
return "(None)";
|
return "(None)";
|
||||||
|
|
||||||
for (iter = FP->tests.begin(); iter != FP->tests.end(); iter++) {
|
for (int j = 0; j < NUM_FPTESTS; j++) {
|
||||||
|
const FingerTest &ft = FP->tests[j];
|
||||||
|
if (ft.id == FingerPrintDef::INVALID)
|
||||||
|
continue;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = test2str(&*iter, p, sizeof(str) - (p - str));
|
len = test2str(&ft, p, sizeof(str) - (p - str));
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
break;
|
break;
|
||||||
p += len;
|
p += len;
|
||||||
@@ -887,7 +872,7 @@ static void parse_cpeline(FingerPrint *FP, const char *thisline, const char *lin
|
|||||||
which some partial fingerpritns are OK. */
|
which some partial fingerpritns are OK. */
|
||||||
/* This function is not currently used by Nmap, but it is present here because
|
/* This function is not currently used by Nmap, but it is present here because
|
||||||
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(const char *fprint) {
|
FingerPrint *parse_single_fingerprint(const FingerPrintDB *DB, const char *fprint) {
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
const char *p, *q;
|
const char *p, *q;
|
||||||
const char *thisline, *nextline;
|
const char *thisline, *nextline;
|
||||||
@@ -938,15 +923,16 @@ FingerPrint *parse_single_fingerprint(const char *fprint) {
|
|||||||
parse_cpeline(FP, thisline, nextline, lineno);
|
parse_cpeline(FP, thisline, nextline, lineno);
|
||||||
|
|
||||||
} else if ((q = strchr_p(thisline, nextline, '('))) {
|
} else if ((q = strchr_p(thisline, nextline, '('))) {
|
||||||
FingerTest test;
|
FingerTest test(FPstr(thisline, q), *DB->MatchPoints);
|
||||||
test.name = string_pool_substr(thisline, q);
|
|
||||||
p = q+1;
|
p = q+1;
|
||||||
q = strchr_p(p, nextline, ')');
|
q = strchr_p(p, nextline, ')');
|
||||||
if (!q) {
|
if (!q) {
|
||||||
fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
|
fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
|
||||||
}
|
}
|
||||||
test.results = str2AVal(p, q);
|
if (!test.str2AVal(p, q)) {
|
||||||
FP->tests.push_back(test);
|
fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
|
||||||
|
}
|
||||||
|
FP->setTest(test);
|
||||||
} else {
|
} else {
|
||||||
fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
|
fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
|
||||||
}
|
}
|
||||||
@@ -985,6 +971,7 @@ top:
|
|||||||
fparse:
|
fparse:
|
||||||
if (strncmp(line, "Fingerprint", 11) == 0) {
|
if (strncmp(line, "Fingerprint", 11) == 0) {
|
||||||
parsingMatchPoints = false;
|
parsingMatchPoints = false;
|
||||||
|
current = new FingerPrint;
|
||||||
} else if (strncmp(line, "MatchPoints", 11) == 0) {
|
} else if (strncmp(line, "MatchPoints", 11) == 0) {
|
||||||
if (DB->MatchPoints)
|
if (DB->MatchPoints)
|
||||||
fatal("Found MatchPoints directive on line %d of %s even though it has previously been seen in the file", lineno, fname);
|
fatal("Found MatchPoints directive on line %d of %s even though it has previously been seen in the file", lineno, fname);
|
||||||
@@ -994,11 +981,8 @@ fparse:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = new FingerPrint;
|
|
||||||
|
|
||||||
if (parsingMatchPoints) {
|
if (parsingMatchPoints) {
|
||||||
current->match.OS_name = NULL;
|
DB->MatchPoints = new FingerPrintDef();
|
||||||
DB->MatchPoints = current;
|
|
||||||
} else {
|
} else {
|
||||||
DB->prints.push_back(current);
|
DB->prints.push_back(current);
|
||||||
p = line + 12;
|
p = line + 12;
|
||||||
@@ -1016,9 +1000,9 @@ fparse:
|
|||||||
fatal("Parse error on line %d of fingerprint: %s", lineno, line);
|
fatal("Parse error on line %d of fingerprint: %s", lineno, line);
|
||||||
|
|
||||||
current->match.OS_name = cp_strndup(p, q - p + 1);
|
current->match.OS_name = cp_strndup(p, q - p + 1);
|
||||||
}
|
|
||||||
|
|
||||||
current->match.line = lineno;
|
current->match.line = lineno;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now we read the fingerprint itself */
|
/* Now we read the fingerprint itself */
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
@@ -1030,34 +1014,37 @@ fparse:
|
|||||||
|
|
||||||
q = strchr(line, '\n');
|
q = strchr(line, '\n');
|
||||||
|
|
||||||
if (!strncmp(line, "Fingerprint ",12)) {
|
if (0 == strncmp(line, "Fingerprint ",12)) {
|
||||||
goto fparse;
|
goto fparse;
|
||||||
|
} else if (parsingMatchPoints) {
|
||||||
|
if (!DB->MatchPoints->parseTestStr(line, q)) {
|
||||||
|
fatal("Parse error in MatchPoints on line %d of nmap-os-db file: %s", lineno, line);
|
||||||
|
}
|
||||||
} else if (strncmp(line, "Class ", 6) == 0) {
|
} else if (strncmp(line, "Class ", 6) == 0) {
|
||||||
parse_classline(current, line, q, lineno);
|
parse_classline(current, line, q, lineno);
|
||||||
} else if (strncmp(line, "CPE ", 4) == 0) {
|
} else if (strncmp(line, "CPE ", 4) == 0) {
|
||||||
parse_cpeline(current, line, q, lineno);
|
parse_cpeline(current, line, q, lineno);
|
||||||
} else {
|
} else {
|
||||||
FingerTest test;
|
|
||||||
p = line;
|
p = line;
|
||||||
q = strchr(line, '(');
|
q = strchr(line, '(');
|
||||||
if (!q) {
|
if (!q) {
|
||||||
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
|
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
|
||||||
goto top;
|
goto top;
|
||||||
}
|
}
|
||||||
test.name = string_pool_substr(p, q);
|
FingerTest test(FPstr(p, q), *DB->MatchPoints);
|
||||||
p = q+1;
|
p = q+1;
|
||||||
q = strchr(p, ')');
|
q = strchr(p, ')');
|
||||||
if (!q) {
|
if (!q) {
|
||||||
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
|
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
|
||||||
goto top;
|
goto top;
|
||||||
}
|
}
|
||||||
test.results = str2AVal(p, q);
|
if (!test.str2AVal(p, q)) {
|
||||||
current->tests.push_back(test);
|
error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
|
||||||
|
goto top;
|
||||||
|
}
|
||||||
|
current->setTest(test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* This sorting is important for later comparison of FingerPrints and
|
|
||||||
FingerTests. */
|
|
||||||
current->sort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|||||||
115
osscan.h
115
osscan.h
@@ -67,6 +67,7 @@
|
|||||||
|
|
||||||
#include <nbase.h>
|
#include <nbase.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
class Target;
|
class Target;
|
||||||
class FingerPrintResultsIPv4;
|
class FingerPrintResultsIPv4;
|
||||||
@@ -90,14 +91,74 @@ enum dist_calc_method {
|
|||||||
|
|
||||||
/********************** STRUCTURES ***********************************/
|
/********************** STRUCTURES ***********************************/
|
||||||
|
|
||||||
struct AVal {
|
#define NUM_FPTESTS 13
|
||||||
const char *attribute;
|
// T2-T7 and U1 have 11 attributes each
|
||||||
const char *value;
|
#define FP_MAX_TEST_ATTRS 11
|
||||||
AVal() : attribute(NULL), value(NULL) {}
|
// RIPCK
|
||||||
|
#define FP_MAX_NAME_LEN 5
|
||||||
|
|
||||||
bool operator<(const AVal& other) const {
|
// Short alphanumeric strings.
|
||||||
return strcmp(attribute, other.attribute) < 0;
|
template<u8 _MaxStrLen>
|
||||||
|
struct ShortStr {
|
||||||
|
char str[_MaxStrLen+1];
|
||||||
|
bool trunc;
|
||||||
|
ShortStr() : trunc(false) {memset(str, 0, sizeof(str));}
|
||||||
|
ShortStr(const char *s) { setStr(s); }
|
||||||
|
ShortStr(const char *s, const char *e) { setStr(s, e); }
|
||||||
|
void setStr(const char *in);
|
||||||
|
void setStr(const char *in, const char *end);
|
||||||
|
// Helpers for type conversion
|
||||||
|
operator const char *() const {return this->str;}
|
||||||
|
operator char *() {return this->str;}
|
||||||
|
bool operator==(const ShortStr &other) const {
|
||||||
|
return (!trunc && !other.trunc
|
||||||
|
&& strncmp(str, other.str, _MaxStrLen) == 0);
|
||||||
}
|
}
|
||||||
|
bool operator!=(const ShortStr &other) const {
|
||||||
|
return (trunc || other.trunc
|
||||||
|
|| strncmp(str, other.str, _MaxStrLen) != 0);
|
||||||
|
}
|
||||||
|
bool operator<(const ShortStr &other) const {
|
||||||
|
return (trunc < other.trunc || strncmp(str, other.str, _MaxStrLen) < 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ShortStr<FP_MAX_NAME_LEN> FPstr;
|
||||||
|
|
||||||
|
struct Attr {
|
||||||
|
FPstr name;
|
||||||
|
int points;
|
||||||
|
Attr() : name(), points(0) {}
|
||||||
|
Attr(const char *n) : name(n), points(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FingerTestDef {
|
||||||
|
FPstr name;
|
||||||
|
u8 numAttrs;
|
||||||
|
bool hasR;
|
||||||
|
std::map<FPstr, u8> AttrIdx;
|
||||||
|
std::vector<Attr> Attrs;
|
||||||
|
|
||||||
|
FingerTestDef() : name(), numAttrs(0), hasR(false) {}
|
||||||
|
FingerTestDef(const FPstr &n, const char *a[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ID2INT(_i) static_cast<int>(_i)
|
||||||
|
#define INT2ID(_i) static_cast<FingerPrintDef::TestID>(_i)
|
||||||
|
class FingerPrintDef {
|
||||||
|
public:
|
||||||
|
enum TestID { SEQ, OPS, WIN, ECN, T1, T2, T3, T4, T5, T6, T7, U1, IE, INVALID };
|
||||||
|
static const char *test_attrs[NUM_FPTESTS][FP_MAX_TEST_ATTRS];
|
||||||
|
FingerPrintDef();
|
||||||
|
bool parseTestStr(const char *str, const char *end);
|
||||||
|
FingerTestDef &getTestDef(TestID id) { return TestDefs[ID2INT(id)]; }
|
||||||
|
const FingerTestDef &getTestDef(TestID id) const { return TestDefs[ID2INT(id)]; }
|
||||||
|
int getTestIndex(FPstr testname) { return ID2INT(TestIdx.at(testname)); }
|
||||||
|
TestID str2TestID(FPstr testname) { return TestIdx.at(testname); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<FPstr, TestID> TestIdx;
|
||||||
|
std::vector<FingerTestDef> TestDefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OS_Classification {
|
struct OS_Classification {
|
||||||
@@ -124,30 +185,46 @@ struct FingerMatch {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FingerPrintDB;
|
||||||
struct FingerTest {
|
struct FingerTest {
|
||||||
const char *name;
|
FingerPrintDef::TestID id;
|
||||||
std::vector<struct AVal> *results;
|
const FingerTestDef *def;
|
||||||
FingerTest(bool allocResults=false);
|
std::vector<const char *> *results;
|
||||||
|
FingerTest() : id(FingerPrintDef::INVALID), def(NULL), results(NULL) {}
|
||||||
|
FingerTest(const FPstr &testname, FingerPrintDef &Defs) {
|
||||||
|
id = Defs.str2TestID(testname);
|
||||||
|
def = &Defs.getTestDef(id);
|
||||||
|
results = new std::vector<const char *>(def->numAttrs, NULL);
|
||||||
|
}
|
||||||
|
FingerTest(FingerPrintDef::TestID testid, FingerPrintDef &Defs)
|
||||||
|
: id(testid), results(NULL) {
|
||||||
|
def = &Defs.getTestDef(id);
|
||||||
|
results = new std::vector<const char *>(def->numAttrs, NULL);
|
||||||
|
}
|
||||||
~FingerTest() {
|
~FingerTest() {
|
||||||
// name is allocated from string_pool
|
|
||||||
// results must be freed manually
|
// results must be freed manually
|
||||||
}
|
}
|
||||||
bool operator<(const FingerTest& other) const {
|
|
||||||
return strcmp(name, other.name) < 0;
|
|
||||||
}
|
|
||||||
void erase();
|
void erase();
|
||||||
|
bool str2AVal(const char *str, const char *end);
|
||||||
|
void setAVal(const char *attr, const char *value);
|
||||||
|
const char *getAVal(const char *attr);
|
||||||
|
const char *getAValName(u8 index) const;
|
||||||
|
const char *getTestName() const { return def->name.str; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FingerPrint {
|
struct FingerPrint {
|
||||||
FingerMatch match;
|
FingerMatch match;
|
||||||
std::vector<FingerTest> tests;
|
FingerTest tests[NUM_FPTESTS];
|
||||||
void sort();
|
|
||||||
void erase();
|
void erase();
|
||||||
|
void setTest(const FingerTest &test) {
|
||||||
|
tests[ID2INT(test.id)] = test;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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) */
|
||||||
struct FingerPrintDB {
|
struct FingerPrintDB {
|
||||||
FingerPrint *MatchPoints;
|
FingerPrintDef *MatchPoints;
|
||||||
std::vector<FingerPrint *> prints;
|
std::vector<FingerPrint *> prints;
|
||||||
|
|
||||||
FingerPrintDB();
|
FingerPrintDB();
|
||||||
@@ -162,7 +239,7 @@ const char *fp2ascii(const FingerPrint *FP);
|
|||||||
non-null fingerprint is returned, the user is in charge of freeing it
|
non-null fingerprint is returned, the user is in charge of freeing it
|
||||||
when done. This function does not require the fingerprint to be 100%
|
when done. This function does not require the fingerprint to be 100%
|
||||||
complete since it is used by scripts such as scripts/fingerwatch for
|
complete since it is used by scripts such as scripts/fingerwatch for
|
||||||
which some partial fingerpritns are OK. */
|
which some partial fingerprints are OK. */
|
||||||
FingerPrint *parse_single_fingerprint(const char *fprint_orig);
|
FingerPrint *parse_single_fingerprint(const char *fprint_orig);
|
||||||
|
|
||||||
/* These functions take a file/db name and open+parse it, returning an
|
/* These functions take a file/db name and open+parse it, returning an
|
||||||
@@ -176,10 +253,10 @@ void free_fingerprint_file(FingerPrintDB *DB);
|
|||||||
/* Compares 2 fingerprints -- a referenceFP (can have expression
|
/* Compares 2 fingerprints -- a referenceFP (can have expression
|
||||||
attributes) with an observed fingerprint (no expressions). If
|
attributes) with an observed fingerprint (no expressions). If
|
||||||
verbose is nonzero, differences will be printed. The comparison
|
verbose is nonzero, differences will be printed. The comparison
|
||||||
accuracy (between 0 and 1) is returned). If MatchPoints is not NULL, it 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 FingerPrint *MatchPoints, int verbose);
|
const FingerPrintDef *MatchPoints, int verbose);
|
||||||
|
|
||||||
/* 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
|
||||||
|
|||||||
448
osscan2.cc
448
osscan2.cc
@@ -134,42 +134,36 @@ static struct scan_performance_vars perf;
|
|||||||
* Miscellaneous functions *
|
* Miscellaneous functions *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/* Fill in a struct AVal with a value based on the IP ID sequence generation
|
/* Return a value based on the IP ID sequence generation
|
||||||
class (one of the IPID_SEQ_* constants). If ipid_seqclass is such that the
|
class (one of the IPID_SEQ_* constants). If ipid_seqclass is such that the
|
||||||
test result should be omitted, the function returns NULL and doesn't modify
|
test result should be omitted, the function returns NULL. */
|
||||||
*av. Otherwise, it returns av after filling in the information. */
|
static const char *make_aval_ipid_seq(int ipid_seqclass, u32 ipids[NUM_SEQ_SAMPLES],
|
||||||
static struct AVal *make_aval_ipid_seq(struct AVal *av, const char *attribute,
|
|
||||||
int ipid_seqclass, u32 ipids[NUM_SEQ_SAMPLES],
|
|
||||||
HostOsScanStats *hss) {
|
HostOsScanStats *hss) {
|
||||||
switch (ipid_seqclass) {
|
switch (ipid_seqclass) {
|
||||||
case IPID_SEQ_CONSTANT:
|
case IPID_SEQ_CONSTANT:
|
||||||
av->value = hss->target->FPR->cp_hex(ipids[0]);
|
return hss->target->FPR->cp_hex(ipids[0]);
|
||||||
break;
|
break;
|
||||||
case IPID_SEQ_INCR_BY_2:
|
case IPID_SEQ_INCR_BY_2:
|
||||||
case IPID_SEQ_INCR:
|
case IPID_SEQ_INCR:
|
||||||
av->value = "I";
|
return "I";
|
||||||
break;
|
break;
|
||||||
case IPID_SEQ_BROKEN_INCR:
|
case IPID_SEQ_BROKEN_INCR:
|
||||||
av->value = "BI";
|
return "BI";
|
||||||
break;
|
break;
|
||||||
case IPID_SEQ_RPI:
|
case IPID_SEQ_RPI:
|
||||||
av->value = "RI";
|
return "RI";
|
||||||
break;
|
break;
|
||||||
case IPID_SEQ_RD:
|
case IPID_SEQ_RD:
|
||||||
av->value = "RD";
|
return "RD";
|
||||||
break;
|
break;
|
||||||
case IPID_SEQ_ZERO:
|
case IPID_SEQ_ZERO:
|
||||||
av->value = "Z";
|
return "Z";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Signal to omit test result. */
|
/* Signal to omit test result. */
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
av->attribute = attribute;
|
|
||||||
|
|
||||||
return av;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1034,12 +1028,6 @@ HostOsScanStats::~HostOsScanStats() {
|
|||||||
FPtests[i] = NULL;
|
FPtests[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
if (TOps_AVs[i])
|
|
||||||
free(TOps_AVs[i]);
|
|
||||||
if (TWin_AVs[i])
|
|
||||||
free(TWin_AVs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!probesToSend.empty()) {
|
while (!probesToSend.empty()) {
|
||||||
delete probesToSend.front();
|
delete probesToSend.front();
|
||||||
@@ -1156,10 +1144,6 @@ void HostOsScanStats::initScanStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < 6; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
if (TOps_AVs[i])
|
|
||||||
free(TOps_AVs[i]);
|
|
||||||
if (TWin_AVs[i])
|
|
||||||
free(TWin_AVs[i]);
|
|
||||||
TOps_AVs[i] = NULL;
|
TOps_AVs[i] = NULL;
|
||||||
TWin_AVs[i] = NULL;
|
TWin_AVs[i] = NULL;
|
||||||
}
|
}
|
||||||
@@ -2029,10 +2013,6 @@ void HostOsScan::makeFP(HostOsScanStats *hss) {
|
|||||||
assert(hss);
|
assert(hss);
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
struct AVal AV;
|
|
||||||
std::vector<struct AVal>::iterator it;
|
|
||||||
|
|
||||||
int ttl;
|
|
||||||
|
|
||||||
if (!hss->FP_TSeq)
|
if (!hss->FP_TSeq)
|
||||||
makeTSeqFP(hss);
|
makeTSeqFP(hss);
|
||||||
@@ -2051,35 +2031,31 @@ void HostOsScan::makeFP(HostOsScanStats *hss) {
|
|||||||
/* We create a Resp (response) attribute with value of N (no) because
|
/* We create a Resp (response) attribute with value of N (no) because
|
||||||
it is important here to note whether responses were or were not
|
it is important here to note whether responses were or were not
|
||||||
received */
|
received */
|
||||||
hss->FPtests[i] = new FingerTest(true);
|
hss->FPtests[i] = new FingerTest(INT2ID(i), *o.reference_FPs->MatchPoints);
|
||||||
AV.attribute = "R";
|
hss->FPtests[i]->setAVal("R", "N");
|
||||||
AV.value = "N";
|
|
||||||
hss->FPtests[i]->results->push_back(AV);
|
|
||||||
hss->FPtests[i]->name = (i == 3)? "ECN" : (i == 4)? "T1" : (i == 5)? "T2" : (i == 6)? "T3" : (i == 7)? "T4" : (i == 8)? "T5" : (i == 9)? "T6" : (i == 10)? "T7" : (i == 11)? "U1" : "IE";
|
|
||||||
}
|
}
|
||||||
else if (hss->FPtests[i]) {
|
else if (hss->FPtests[i]) {
|
||||||
/* Replace TTL with initial TTL. */
|
FingerTest &test = *hss->FPtests[i];
|
||||||
for (it = hss->FPtests[i]->results->begin(); it != hss->FPtests[i]->results->end(); it++) {
|
/* The value for this attribute is the
|
||||||
if (strcmp(it->attribute, "T") == 0) {
|
* received TTL. We replace it with the initial TTL. */
|
||||||
/* Found TTL item. The value for this attribute is the
|
const char *recvTTL = test.getAVal("T");
|
||||||
* received TTL. We replace it with the initial TTL. */
|
if (recvTTL) {
|
||||||
ttl = strtol(it->value, NULL, 16);
|
int ttl = strtol(recvTTL, NULL, 16);
|
||||||
|
|
||||||
if (hss->distance_guess == -1)
|
if (hss->distance_guess == -1)
|
||||||
hss->distance_guess = get_initial_ttl_guess(ttl) - ttl;
|
hss->distance_guess = get_initial_ttl_guess(ttl) - ttl;
|
||||||
|
|
||||||
if (hss->distance != -1) {
|
if (hss->distance != -1) {
|
||||||
/* We've gotten response for the UDP probe and thus have
|
/* We've gotten response for the UDP probe and thus have
|
||||||
the "true" hop count. Add the number of hops between
|
the "true" hop count. Add the number of hops between
|
||||||
us and the target (hss->distance - 1) to the received
|
us and the target (hss->distance - 1) to the received
|
||||||
TTL to get the initial TTL. */
|
TTL to get the initial TTL. */
|
||||||
it->value = hss->target->FPR->cp_hex(ttl + hss->distance - 1);
|
test.setAVal("T", hss->target->FPR->cp_hex(ttl + hss->distance - 1));
|
||||||
} else {
|
} else {
|
||||||
/* Guess the initial TTL value */
|
/* Guess the initial TTL value */
|
||||||
it->attribute = "TG";
|
test.setAVal("TG", hss->target->FPR->cp_hex(get_initial_ttl_guess(ttl)));
|
||||||
it->value = hss->target->FPR->cp_hex(get_initial_ttl_guess(ttl));
|
/* Delete this unknown-distance-dependent value */
|
||||||
}
|
test.setAVal("T", NULL);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2090,7 +2066,7 @@ void HostOsScan::makeFP(HostOsScanStats *hss) {
|
|||||||
for (i = 0; i < NUM_FPTESTS; i++) {
|
for (i = 0; i < NUM_FPTESTS; i++) {
|
||||||
if (hss->FPtests[i] == NULL)
|
if (hss->FPtests[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
hss->FP->tests.push_back(*hss->FPtests[i]);
|
hss->FP->tests[i] = *hss->FPtests[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2314,11 +2290,8 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
int good_tcp_ipid_num, good_tcp_closed_ipid_num, good_icmp_ipid_num;
|
int good_tcp_ipid_num, good_tcp_closed_ipid_num, good_icmp_ipid_num;
|
||||||
int tsnewval = 0;
|
int tsnewval = 0;
|
||||||
|
|
||||||
std::vector<struct AVal> *seq_AVs = new std::vector<struct AVal>;
|
hss->FP_TSeq = new FingerTest(FingerPrintDef::SEQ, *o.reference_FPs->MatchPoints);
|
||||||
struct AVal AV;
|
FingerTest &test = *hss->FP_TSeq;
|
||||||
|
|
||||||
/* Need 8 AVals for SP, GCD, ISR, TI, CI, II, SS, TS. */
|
|
||||||
seq_AVs->reserve(8);
|
|
||||||
|
|
||||||
/* Now we make sure there are no gaps in our response array ... */
|
/* Now we make sure there are no gaps in our response array ... */
|
||||||
for (i = 0, j = 0; i < NUM_SEQ_SAMPLES; i++) {
|
for (i = 0, j = 0; i < NUM_SEQ_SAMPLES; i++) {
|
||||||
@@ -2399,15 +2372,9 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AV.attribute = "SP";
|
test.setAVal("SP", hss->target->FPR->cp_hex(hss->si.index));
|
||||||
AV.value = hss->target->FPR->cp_hex(hss->si.index);
|
test.setAVal("GCD", hss->target->FPR->cp_hex(seq_gcd));
|
||||||
seq_AVs->push_back(AV);
|
test.setAVal("ISR", hss->target->FPR->cp_hex((unsigned int) seq_rate));
|
||||||
AV.attribute = "GCD";
|
|
||||||
AV.value = hss->target->FPR->cp_hex(seq_gcd);
|
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
AV.attribute = "ISR";
|
|
||||||
AV.value = hss->target->FPR->cp_hex((unsigned int) seq_rate);
|
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
} else if (hss->si.responses > 0) {
|
} else if (hss->si.responses > 0) {
|
||||||
if (o.debugging)
|
if (o.debugging)
|
||||||
log_write(LOG_PLAIN, "Insufficient responses from %s for TCP sequencing (%d), OS detection may be less accurate\n", hss->target->targetipstr(), hss->si.responses);
|
log_write(LOG_PLAIN, "Insufficient responses from %s for TCP sequencing (%d), OS detection may be less accurate\n", hss->target->targetipstr(), hss->si.responses);
|
||||||
@@ -2462,12 +2429,9 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This fills in TI=Z or something like that. */
|
/* This fills in TI=Z or something like that. */
|
||||||
if (make_aval_ipid_seq(&AV, "TI", tcp_ipid_seqclass, hss->ipid.tcp_ipids, hss) != NULL)
|
test.setAVal("TI", make_aval_ipid_seq(tcp_ipid_seqclass, hss->ipid.tcp_ipids, hss));
|
||||||
seq_AVs->push_back(AV);
|
test.setAVal("CI", make_aval_ipid_seq(tcp_closed_ipid_seqclass, hss->ipid.tcp_closed_ipids, hss));
|
||||||
if (make_aval_ipid_seq(&AV, "CI", tcp_closed_ipid_seqclass, hss->ipid.tcp_closed_ipids, hss) != NULL)
|
test.setAVal("II", make_aval_ipid_seq(icmp_ipid_seqclass, hss->ipid.icmp_ipids, hss));
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
if (make_aval_ipid_seq(&AV, "II", icmp_ipid_seqclass, hss->ipid.icmp_ipids, hss) != NULL)
|
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* SS: Shared IP ID sequence boolean */
|
/* SS: Shared IP ID sequence boolean */
|
||||||
if ((tcp_ipid_seqclass == IPID_SEQ_INCR ||
|
if ((tcp_ipid_seqclass == IPID_SEQ_INCR ||
|
||||||
@@ -2478,14 +2442,12 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
icmp_ipid_seqclass == IPID_SEQ_RPI)) {
|
icmp_ipid_seqclass == IPID_SEQ_RPI)) {
|
||||||
/* Both are incremental. Thus we have "SS" test. Check if they
|
/* Both are incremental. Thus we have "SS" test. Check if they
|
||||||
are in the same sequence. */
|
are in the same sequence. */
|
||||||
AV.attribute = "SS";
|
|
||||||
u32 avg = (hss->ipid.tcp_ipids[good_tcp_ipid_num - 1] - hss->ipid.tcp_ipids[0]) / (good_tcp_ipid_num - 1);
|
u32 avg = (hss->ipid.tcp_ipids[good_tcp_ipid_num - 1] - hss->ipid.tcp_ipids[0]) / (good_tcp_ipid_num - 1);
|
||||||
if (hss->ipid.icmp_ipids[0] < hss->ipid.tcp_ipids[good_tcp_ipid_num - 1] + 3 * avg) {
|
if (hss->ipid.icmp_ipids[0] < hss->ipid.tcp_ipids[good_tcp_ipid_num - 1] + 3 * avg) {
|
||||||
AV.value = "S";
|
test.setAVal("SS", "S");
|
||||||
} else {
|
} else {
|
||||||
AV.value = "O";
|
test.setAVal("SS", "O");
|
||||||
}
|
}
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we look at TCP Timestamp sequence prediction */
|
/* Now we look at TCP Timestamp sequence prediction */
|
||||||
@@ -2541,16 +2503,12 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
switch (hss->si.ts_seqclass) {
|
switch (hss->si.ts_seqclass) {
|
||||||
|
|
||||||
case TS_SEQ_ZERO:
|
case TS_SEQ_ZERO:
|
||||||
AV.attribute = "TS";
|
test.setAVal("TS", "0");
|
||||||
AV.value = "0";
|
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
break;
|
break;
|
||||||
case TS_SEQ_2HZ:
|
case TS_SEQ_2HZ:
|
||||||
case TS_SEQ_100HZ:
|
case TS_SEQ_100HZ:
|
||||||
case TS_SEQ_1000HZ:
|
case TS_SEQ_1000HZ:
|
||||||
case TS_SEQ_OTHER_NUM:
|
case TS_SEQ_OTHER_NUM:
|
||||||
AV.attribute = "TS";
|
|
||||||
|
|
||||||
/* Here we "cheat" a little to make the classes correspond more
|
/* Here we "cheat" a little to make the classes correspond more
|
||||||
closely to common real-life frequencies (particularly 100)
|
closely to common real-life frequencies (particularly 100)
|
||||||
which aren't powers of two. */
|
which aren't powers of two. */
|
||||||
@@ -2572,26 +2530,12 @@ void HostOsScan::makeTSeqFP(HostOsScanStats *hss) {
|
|||||||
tsnewval = (unsigned int)(0.5 + log(avg_ts_hz) / log(2.0));
|
tsnewval = (unsigned int)(0.5 + log(avg_ts_hz) / log(2.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
AV.value = hss->target->FPR->cp_hex(tsnewval);
|
test.setAVal("TS", hss->target->FPR->cp_hex(tsnewval));
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
break;
|
break;
|
||||||
case TS_SEQ_UNSUPPORTED:
|
case TS_SEQ_UNSUPPORTED:
|
||||||
AV.attribute = "TS";
|
test.setAVal("TS", "U");
|
||||||
AV.value = "U";
|
|
||||||
seq_AVs->push_back(AV);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now generate the SEQ line of the fingerprint if there are any test results
|
|
||||||
in seq_AVs. */
|
|
||||||
if (!seq_AVs->empty()) {
|
|
||||||
hss->FP_TSeq = new FingerTest;
|
|
||||||
hss->FP_TSeq->name = "SEQ";
|
|
||||||
hss->FP_TSeq->results = seq_AVs;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delete seq_AVs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2612,15 +2556,11 @@ void HostOsScan::makeTOpsFP(HostOsScanStats *hss) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
hss->FP_TOps = new FingerTest(FingerPrintDef::OPS, *o.reference_FPs->MatchPoints);
|
||||||
AVs->reserve(n);
|
std::vector<const char *> &results = *hss->FP_TOps->results;
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
AVs->push_back(*hss->TOps_AVs[i]);
|
results[i] = hss->TOps_AVs[i];
|
||||||
|
|
||||||
hss->FP_TOps = new FingerTest;
|
|
||||||
hss->FP_TOps->results = AVs;
|
|
||||||
hss->FP_TOps->name = "OPS";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2641,15 +2581,11 @@ void HostOsScan::makeTWinFP(HostOsScanStats *hss) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
hss->FP_TWin = new FingerTest(FingerPrintDef::WIN, *o.reference_FPs->MatchPoints);
|
||||||
AVs->reserve(n);
|
std::vector<const char *> &results = *hss->FP_TWin->results;
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
AVs->push_back(*hss->TWin_AVs[i]);
|
results[i] = hss->TWin_AVs[i];
|
||||||
|
|
||||||
hss->FP_TWin = new FingerTest;
|
|
||||||
hss->FP_TWin->results = AVs;
|
|
||||||
hss->FP_TWin->name = "WIN";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2727,37 +2663,15 @@ bool HostOsScan::processTOpsResp(HostOsScanStats *hss, const struct tcp_hdr *tcp
|
|||||||
if (hss->FP_TOps || hss->TOps_AVs[replyNo])
|
if (hss->FP_TOps || hss->TOps_AVs[replyNo])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hss->TOps_AVs[replyNo] = (struct AVal *) safe_zalloc(sizeof(struct AVal));
|
|
||||||
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
||||||
|
|
||||||
if (opsParseResult <= 0) {
|
if (opsParseResult <= 0) {
|
||||||
if (opsParseResult < 0 && o.debugging)
|
if (opsParseResult < 0 && o.debugging)
|
||||||
error("Option parse error for TOps response %d from %s.", replyNo, hss->target->targetipstr());
|
error("Option parse error for TOps response %d from %s.", replyNo, hss->target->targetipstr());
|
||||||
hss->TOps_AVs[replyNo]->value = "";
|
hss->TOps_AVs[replyNo] = "";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hss->TOps_AVs[replyNo]->value = hss->target->FPR->cp_dup(ops_buf, opsParseResult);
|
hss->TOps_AVs[replyNo] = hss->target->FPR->cp_dup(ops_buf, opsParseResult);
|
||||||
}
|
|
||||||
|
|
||||||
switch (replyNo) {
|
|
||||||
case 0:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O1";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O2";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O3";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O4";
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O5";
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
hss->TOps_AVs[replyNo]->attribute = "O6";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hss->TOpsReplyNum++;
|
hss->TOpsReplyNum++;
|
||||||
@@ -2771,29 +2685,7 @@ bool HostOsScan::processTWinResp(HostOsScanStats *hss, const struct tcp_hdr *tcp
|
|||||||
if (hss->FP_TWin || hss->TWin_AVs[replyNo])
|
if (hss->FP_TWin || hss->TWin_AVs[replyNo])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hss->TWin_AVs[replyNo] = (struct AVal *) safe_zalloc(sizeof(struct AVal));
|
hss->TWin_AVs[replyNo] = hss->target->FPR->cp_hex(ntohs(tcp->th_win));
|
||||||
hss->TWin_AVs[replyNo]->value = hss->target->FPR->cp_hex(ntohs(tcp->th_win));
|
|
||||||
|
|
||||||
switch (replyNo) {
|
|
||||||
case 0:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W1";
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W2";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W3";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W4";
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W5";
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
hss->TWin_AVs[replyNo]->attribute = "W6";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hss->TWinReplyNum++;
|
hss->TWinReplyNum++;
|
||||||
return true;
|
return true;
|
||||||
@@ -2801,73 +2693,58 @@ bool HostOsScan::processTWinResp(HostOsScanStats *hss, const struct tcp_hdr *tcp
|
|||||||
|
|
||||||
|
|
||||||
bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
|
bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
|
||||||
struct AVal AV;
|
|
||||||
char ops_buf[256];
|
char ops_buf[256];
|
||||||
char quirks_buf[10];
|
char quirks_buf[10];
|
||||||
char *p;
|
char *p;
|
||||||
int numtests = 7;
|
|
||||||
const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
||||||
|
|
||||||
if (hss->FP_TEcn)
|
if (hss->FP_TEcn)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Create the Avals */
|
/* Create the Avals */
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
hss->FP_TEcn = new FingerTest(FingerPrintDef::ECN, *o.reference_FPs->MatchPoints);
|
||||||
AVs->reserve(numtests);
|
FingerTest &test = *hss->FP_TEcn;
|
||||||
|
|
||||||
AV.attribute = "R";
|
test.setAVal("R", "Y");
|
||||||
AV.value = "Y";
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* don't frag flag */
|
/* don't frag flag */
|
||||||
AV.attribute = "DF";
|
|
||||||
if (ntohs(ip->ip_off) & IP_DF)
|
if (ntohs(ip->ip_off) & IP_DF)
|
||||||
AV.value = "Y";
|
test.setAVal("DF", "Y");
|
||||||
else
|
else
|
||||||
AV.value = "N";
|
test.setAVal("DF", "N");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TTL */
|
/* TTL */
|
||||||
AV.attribute = "T";
|
test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl));
|
||||||
AV.value = hss->target->FPR->cp_hex(ip->ip_ttl);
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TCP Window size */
|
/* TCP Window size */
|
||||||
AV.attribute = "W";
|
test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp->th_win)));
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(tcp->th_win));
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Now for the TCP options ... */
|
/* Now for the TCP options ... */
|
||||||
AV.attribute = "O";
|
|
||||||
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
||||||
|
|
||||||
if (opsParseResult <= 0) {
|
if (opsParseResult <= 0) {
|
||||||
if (opsParseResult < 0 && o.debugging)
|
if (opsParseResult < 0 && o.debugging)
|
||||||
error("Option parse error for ECN response from %s.", hss->target->targetipstr());
|
error("Option parse error for ECN response from %s.", hss->target->targetipstr());
|
||||||
AV.value = "";
|
test.setAVal("O", "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AV.value = hss->target->FPR->cp_dup(ops_buf, opsParseResult);
|
test.setAVal("O", hss->target->FPR->cp_dup(ops_buf, opsParseResult));
|
||||||
}
|
}
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Explicit Congestion Notification support test */
|
/* Explicit Congestion Notification support test */
|
||||||
AV.attribute = "CC";
|
|
||||||
if ((tcp->th_flags & TH_ECE) && (tcp->th_flags & TH_CWR))
|
if ((tcp->th_flags & TH_ECE) && (tcp->th_flags & TH_CWR))
|
||||||
/* echo back */
|
/* echo back */
|
||||||
AV.value = "S";
|
test.setAVal("CC", "S");
|
||||||
else if (tcp->th_flags & TH_ECE)
|
else if (tcp->th_flags & TH_ECE)
|
||||||
/* support */
|
/* support */
|
||||||
AV.value = "Y";
|
test.setAVal("CC", "Y");
|
||||||
else if (!(tcp->th_flags & TH_CWR))
|
else if (!(tcp->th_flags & TH_CWR))
|
||||||
/* not support */
|
/* not support */
|
||||||
AV.value = "N";
|
test.setAVal("CC", "N");
|
||||||
else
|
else
|
||||||
AV.value = "O";
|
test.setAVal("CC", "O");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TCP miscellaneous quirks test */
|
/* TCP miscellaneous quirks test */
|
||||||
AV.attribute = "Q";
|
|
||||||
p = quirks_buf;
|
p = quirks_buf;
|
||||||
if (tcp->th_x2) {
|
if (tcp->th_x2) {
|
||||||
/* Reserved field of TCP is not zero */
|
/* Reserved field of TCP is not zero */
|
||||||
@@ -2880,22 +2757,15 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) {
|
|||||||
*p++ = 'U';
|
*p++ = 'U';
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
AV.value = hss->target->FPR->cp_dup(quirks_buf, p - quirks_buf);
|
test.setAVal("Q", hss->target->FPR->cp_dup(quirks_buf, p - quirks_buf));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
hss->FP_TEcn = new FingerTest;
|
|
||||||
hss->FP_TEcn->name = "ECN";
|
|
||||||
hss->FP_TEcn->results = AVs;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
|
bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
|
||||||
struct AVal AV;
|
|
||||||
assert(replyNo >= 0 && replyNo < 7);
|
assert(replyNo >= 0 && replyNo < 7);
|
||||||
|
|
||||||
int numtests;
|
|
||||||
const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl));
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
@@ -2903,42 +2773,30 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
char flags_buf[10];
|
char flags_buf[10];
|
||||||
char quirks_buf[10];
|
char quirks_buf[10];
|
||||||
char *p;
|
char *p;
|
||||||
|
FingerPrintDef::TestID testid = INT2ID(ID2INT(FingerPrintDef::T1) + replyNo);
|
||||||
|
|
||||||
if (hss->FPtests[FP_T1_7_OFF + replyNo])
|
if (hss->FPtests[FP_T1_7_OFF + replyNo])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (replyNo == 0)
|
hss->FPtests[FP_T1_7_OFF + replyNo] = new FingerTest(testid, *o.reference_FPs->MatchPoints);
|
||||||
numtests = 8; /* T1 doesn't has 'Win', 'Ops' tests. */
|
FingerTest &test = *hss->FPtests[FP_T1_7_OFF + replyNo];
|
||||||
else numtests = 10;
|
|
||||||
|
|
||||||
/* Create the Avals */
|
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
|
||||||
AVs->reserve(numtests);
|
|
||||||
|
|
||||||
/* First we give the "response" flag to say we did actually receive
|
/* First we give the "response" flag to say we did actually receive
|
||||||
a packet -- this way we won't match a template with R=N */
|
a packet -- this way we won't match a template with R=N */
|
||||||
AV.attribute = "R";
|
test.setAVal("R", "Y");
|
||||||
AV.value = "Y";
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Next we check whether the Don't Fragment bit is set */
|
/* Next we check whether the Don't Fragment bit is set */
|
||||||
AV.attribute = "DF";
|
|
||||||
if (ntohs(ip->ip_off) & IP_DF)
|
if (ntohs(ip->ip_off) & IP_DF)
|
||||||
AV.value = "Y";
|
test.setAVal("DF", "Y");
|
||||||
else
|
else
|
||||||
AV.value = "N";
|
test.setAVal("DF", "N");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TTL */
|
/* TTL */
|
||||||
AV.attribute = "T";
|
test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl));
|
||||||
AV.value = hss->target->FPR->cp_hex(ip->ip_ttl);
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
if (replyNo != 0) {
|
if (replyNo != 0) {
|
||||||
/* Now we do the TCP Window size */
|
/* Now we do the TCP Window size */
|
||||||
AV.attribute = "W";
|
test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp->th_win)));
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(tcp->th_win));
|
|
||||||
AVs->push_back(AV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Seq test values:
|
/* Seq test values:
|
||||||
@@ -2947,16 +2805,14 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
A+ = ack + 1
|
A+ = ack + 1
|
||||||
O = other
|
O = other
|
||||||
*/
|
*/
|
||||||
AV.attribute = "S";
|
|
||||||
if (ntohl(tcp->th_seq) == 0)
|
if (ntohl(tcp->th_seq) == 0)
|
||||||
AV.value = "Z";
|
test.setAVal("S", "Z");
|
||||||
else if (ntohl(tcp->th_seq) == tcpAck)
|
else if (ntohl(tcp->th_seq) == tcpAck)
|
||||||
AV.value = "A";
|
test.setAVal("S", "A");
|
||||||
else if (ntohl(tcp->th_seq) == tcpAck + 1)
|
else if (ntohl(tcp->th_seq) == tcpAck + 1)
|
||||||
AV.value = "A+";
|
test.setAVal("S", "A+");
|
||||||
else
|
else
|
||||||
AV.value = "O";
|
test.setAVal("S", "O");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* ACK test values:
|
/* ACK test values:
|
||||||
Z = zero
|
Z = zero
|
||||||
@@ -2964,16 +2820,14 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
S+ = syn + 1
|
S+ = syn + 1
|
||||||
O = other
|
O = other
|
||||||
*/
|
*/
|
||||||
AV.attribute = "A";
|
|
||||||
if (ntohl(tcp->th_ack) == 0)
|
if (ntohl(tcp->th_ack) == 0)
|
||||||
AV.value = "Z";
|
test.setAVal("A", "Z");
|
||||||
else if (ntohl(tcp->th_ack) == tcpSeqBase)
|
else if (ntohl(tcp->th_ack) == tcpSeqBase)
|
||||||
AV.value = "S";
|
test.setAVal("A", "S");
|
||||||
else if (ntohl(tcp->th_ack) == tcpSeqBase + 1)
|
else if (ntohl(tcp->th_ack) == tcpSeqBase + 1)
|
||||||
AV.value = "S+";
|
test.setAVal("A", "S+");
|
||||||
else
|
else
|
||||||
AV.value = "O";
|
test.setAVal("A", "O");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Flags. They must be in this order:
|
/* Flags. They must be in this order:
|
||||||
E = ECN Echo
|
E = ECN Echo
|
||||||
@@ -2997,45 +2851,38 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
{ TH_FIN, 'F' },
|
{ TH_FIN, 'F' },
|
||||||
};
|
};
|
||||||
assert(sizeof(flag_defs) / sizeof(flag_defs[0]) < sizeof(flags_buf));
|
assert(sizeof(flag_defs) / sizeof(flag_defs[0]) < sizeof(flags_buf));
|
||||||
AV.attribute = "F";
|
|
||||||
p = flags_buf;
|
p = flags_buf;
|
||||||
for (i = 0; i < (int) (sizeof(flag_defs) / sizeof(flag_defs[0])); i++) {
|
for (i = 0; i < (int) (sizeof(flag_defs) / sizeof(flag_defs[0])); i++) {
|
||||||
if (tcp->th_flags & flag_defs[i].flag)
|
if (tcp->th_flags & flag_defs[i].flag)
|
||||||
*p++ = flag_defs[i].c;
|
*p++ = flag_defs[i].c;
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
AV.value = hss->target->FPR->cp_dup(flags_buf, p - flags_buf);
|
test.setAVal("F", hss->target->FPR->cp_dup(flags_buf, p - flags_buf));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
if (replyNo != 0) {
|
if (replyNo != 0) {
|
||||||
char ops_buf[256];
|
char ops_buf[256];
|
||||||
|
|
||||||
/* Now for the TCP options ... */
|
/* Now for the TCP options ... */
|
||||||
AV.attribute = "O";
|
|
||||||
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf));
|
||||||
if (opsParseResult <= 0) {
|
if (opsParseResult <= 0) {
|
||||||
if (opsParseResult < 0 && o.debugging)
|
if (opsParseResult < 0 && o.debugging)
|
||||||
error("Option parse error for T%d response from %s.", replyNo, hss->target->targetipstr());
|
error("Option parse error for T%d response from %s.", replyNo, hss->target->targetipstr());
|
||||||
AV.value = "";
|
test.setAVal("O", "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AV.value = hss->target->FPR->cp_dup(ops_buf, opsParseResult);
|
test.setAVal("O", hss->target->FPR->cp_dup(ops_buf, opsParseResult));
|
||||||
}
|
}
|
||||||
AVs->push_back(AV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rst Data CRC32 */
|
/* Rst Data CRC32 */
|
||||||
AV.attribute = "RD";
|
|
||||||
length = (int) ntohs(ip->ip_len) - 4 * ip->ip_hl -4 * tcp->th_off;
|
length = (int) ntohs(ip->ip_len) - 4 * ip->ip_hl -4 * tcp->th_off;
|
||||||
if ((tcp->th_flags & TH_RST) && length>0) {
|
if ((tcp->th_flags & TH_RST) && length>0) {
|
||||||
AV.value = hss->target->FPR->cp_hex(nbase_crc32(((u8 *)tcp) + 4 * tcp->th_off, length));
|
test.setAVal("RD", hss->target->FPR->cp_hex(nbase_crc32(((u8 *)tcp) + 4 * tcp->th_off, length)));
|
||||||
} else {
|
} else {
|
||||||
AV.value = "0";
|
test.setAVal("RD", "0");
|
||||||
}
|
}
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TCP miscellaneous quirks test */
|
/* TCP miscellaneous quirks test */
|
||||||
AV.attribute = "Q";
|
|
||||||
p = quirks_buf;
|
p = quirks_buf;
|
||||||
if (tcp->th_x2) {
|
if (tcp->th_x2) {
|
||||||
/* Reserved field of TCP is not zero */
|
/* Reserved field of TCP is not zero */
|
||||||
@@ -3048,39 +2895,24 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
*p++ = 'U';
|
*p++ = 'U';
|
||||||
}
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
AV.value = hss->target->FPR->cp_dup(quirks_buf, p - quirks_buf);
|
test.setAVal("Q", hss->target->FPR->cp_dup(quirks_buf, p - quirks_buf));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
hss->FPtests[FP_T1_7_OFF + replyNo] = new FingerTest;
|
|
||||||
hss->FPtests[FP_T1_7_OFF + replyNo]->results = AVs;
|
|
||||||
hss->FPtests[FP_T1_7_OFF + replyNo]->name = (replyNo == 0) ? "T1" : (replyNo == 1) ? "T2" : (replyNo == 2) ? "T3" : (replyNo == 3) ? "T4" : (replyNo == 4) ? "T5" : (replyNo == 5) ? "T6" : "T7";
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
|
bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
|
||||||
struct AVal AV;
|
|
||||||
|
|
||||||
assert(hss);
|
assert(hss);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
|
|
||||||
const struct icmp *icmp;
|
const struct icmp *icmp;
|
||||||
const struct ip *ip2;
|
const struct ip *ip2;
|
||||||
int numtests;
|
|
||||||
unsigned short checksum;
|
unsigned short checksum;
|
||||||
unsigned short *checksumptr;
|
unsigned short *checksumptr;
|
||||||
const struct udp_hdr *udp;
|
const struct udp_hdr *udp;
|
||||||
const unsigned char *datastart, *dataend;
|
const unsigned char *datastart, *dataend;
|
||||||
|
|
||||||
#if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX)
|
|
||||||
numtests = 10;
|
|
||||||
#else
|
|
||||||
/* We don't do RID test under these operating systems, thus the
|
|
||||||
number of test is 1 less. */
|
|
||||||
numtests = 9;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (hss->FP_TUdp)
|
if (hss->FP_TUdp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -3097,94 +2929,75 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the Avals */
|
hss->FP_TUdp = new FingerTest(FingerPrintDef::U1, *o.reference_FPs->MatchPoints);
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
FingerTest &test = *hss->FP_TUdp;
|
||||||
AVs->reserve(numtests);
|
|
||||||
|
|
||||||
/* First of all, if we got this far the response was yes */
|
/* First of all, if we got this far the response was yes */
|
||||||
AV.attribute = "R";
|
test.setAVal("R", "Y");
|
||||||
AV.value = "Y";
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Also, we now know that the port we reached was closed */
|
/* Also, we now know that the port we reached was closed */
|
||||||
if (hss->target->FPR->osscan_closedudpport == -1)
|
if (hss->target->FPR->osscan_closedudpport == -1)
|
||||||
hss->target->FPR->osscan_closedudpport = hss->upi.dport;
|
hss->target->FPR->osscan_closedudpport = hss->upi.dport;
|
||||||
|
|
||||||
/* Now let us do an easy one, Don't fragment */
|
/* Now let us do an easy one, Don't fragment */
|
||||||
AV.attribute = "DF";
|
|
||||||
if (ntohs(ip->ip_off) & IP_DF)
|
if (ntohs(ip->ip_off) & IP_DF)
|
||||||
AV.value = "Y";
|
test.setAVal("DF", "Y");
|
||||||
else
|
else
|
||||||
AV.value = "N";
|
test.setAVal("DF", "N");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TTL */
|
/* TTL */
|
||||||
AV.attribute = "T";
|
test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl));
|
||||||
AV.value = hss->target->FPR->cp_hex(ip->ip_ttl);
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Now we look at the IP datagram length that was returned, some
|
/* Now we look at the IP datagram length that was returned, some
|
||||||
machines send more of the original packet back than others */
|
machines send more of the original packet back than others */
|
||||||
AV.attribute = "IPL";
|
test.setAVal("IPL", hss->target->FPR->cp_hex(ntohs(ip->ip_len)));
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(ip->ip_len));
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* unused filed not zero in Destination Unreachable Message */
|
/* unused filed not zero in Destination Unreachable Message */
|
||||||
AV.attribute = "UN";
|
test.setAVal("UN", hss->target->FPR->cp_hex(ntohl(icmp->icmp_void)));
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohl(icmp->icmp_void));
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* OK, lets check the returned IP length, some systems @$@ this
|
/* OK, lets check the returned IP length, some systems @$@ this
|
||||||
up */
|
up */
|
||||||
AV.attribute = "RIPL";
|
|
||||||
if (ntohs(ip2->ip_len) == 328)
|
if (ntohs(ip2->ip_len) == 328)
|
||||||
AV.value = "G";
|
test.setAVal("RIPL", "G");
|
||||||
else
|
else
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(ip2->ip_len));
|
test.setAVal("RIPL", hss->target->FPR->cp_hex(ntohs(ip2->ip_len)));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* This next test doesn't work on Solaris because the lamers
|
/* This next test doesn't work on Solaris because the lamers
|
||||||
overwrite our ip_id */
|
overwrite our ip_id */
|
||||||
#if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX)
|
#if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX)
|
||||||
|
|
||||||
/* Now lets see how they treated the ID we sent ... */
|
/* Now lets see how they treated the ID we sent ... */
|
||||||
AV.attribute = "RID";
|
|
||||||
if (ntohs(ip2->ip_id) == hss->upi.ipid)
|
if (ntohs(ip2->ip_id) == hss->upi.ipid)
|
||||||
AV.value = "G"; /* The good "expected" value */
|
test.setAVal("RID", "G"); /* The good "expected" value */
|
||||||
else
|
else
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(ip2->ip_id));
|
test.setAVal("RID", hss->target->FPR->cp_hex(ntohs(ip2->ip_id)));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Let us see if the IP checksum we got back computes */
|
/* Let us see if the IP checksum we got back computes */
|
||||||
|
|
||||||
AV.attribute = "RIPCK";
|
|
||||||
/* Thanks to some machines not having struct ip member ip_sum we
|
/* Thanks to some machines not having struct ip member ip_sum we
|
||||||
have to go with this BS */
|
have to go with this BS */
|
||||||
checksumptr = (unsigned short *) ((char *) ip2 + 10);
|
checksumptr = (unsigned short *) ((char *) ip2 + 10);
|
||||||
checksum = *checksumptr;
|
checksum = *checksumptr;
|
||||||
|
|
||||||
if (checksum == 0) {
|
if (checksum == 0) {
|
||||||
AV.value = "Z";
|
test.setAVal("RIPCK", "Z");
|
||||||
} else {
|
} else {
|
||||||
*checksumptr = 0;
|
*checksumptr = 0;
|
||||||
if (in_cksum((unsigned short *)ip2, 20) == checksum) {
|
if (in_cksum((unsigned short *)ip2, 20) == checksum) {
|
||||||
AV.value = "G"; /* The "expected" good value */
|
test.setAVal("RIPCK", "G"); /* The "expected" good value */
|
||||||
} else {
|
} else {
|
||||||
AV.value = "I"; /* They modified it */
|
test.setAVal("RIPCK", "I"); /* They modified it */
|
||||||
}
|
}
|
||||||
*checksumptr = checksum;
|
*checksumptr = checksum;
|
||||||
}
|
}
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* UDP checksum */
|
/* UDP checksum */
|
||||||
AV.attribute = "RUCK";
|
|
||||||
if (udp->uh_sum == hss->upi.udpck)
|
if (udp->uh_sum == hss->upi.udpck)
|
||||||
AV.value = "G"; /* The "expected" good value */
|
test.setAVal("RUCK", "G"); /* The "expected" good value */
|
||||||
else
|
else
|
||||||
AV.value = hss->target->FPR->cp_hex(ntohs(udp->uh_sum));
|
test.setAVal("RUCK", hss->target->FPR->cp_hex(ntohs(udp->uh_sum)));
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* Finally we ensure the data is OK */
|
/* Finally we ensure the data is OK */
|
||||||
datastart = ((unsigned char *)udp) + 8;
|
datastart = ((unsigned char *)udp) + 8;
|
||||||
@@ -3195,16 +3008,10 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
|
|||||||
break;
|
break;
|
||||||
datastart++;
|
datastart++;
|
||||||
}
|
}
|
||||||
AV.attribute = "RUD";
|
|
||||||
if (datastart < dataend)
|
if (datastart < dataend)
|
||||||
AV.value = "I"; /* They modified it */
|
test.setAVal("RUD", "I"); /* They modified it */
|
||||||
else
|
else
|
||||||
AV.value = "G";
|
test.setAVal("RUD", "G");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
hss->FP_TUdp = new FingerTest;
|
|
||||||
hss->FP_TUdp->name = "U1";
|
|
||||||
hss->FP_TUdp->results = AVs;
|
|
||||||
|
|
||||||
/* Count hop count */
|
/* Count hop count */
|
||||||
if (hss->distance == -1) {
|
if (hss->distance == -1) {
|
||||||
@@ -3218,8 +3025,6 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) {
|
|||||||
bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
|
bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int replyNo) {
|
||||||
assert(replyNo == 0 || replyNo == 1);
|
assert(replyNo == 0 || replyNo == 1);
|
||||||
|
|
||||||
struct AVal AV;
|
|
||||||
int numtests = 4;
|
|
||||||
const struct ip *ip1, *ip2;
|
const struct ip *ip1, *ip2;
|
||||||
const struct icmp *icmp1, *icmp2;
|
const struct icmp *icmp1, *icmp2;
|
||||||
unsigned short value1, value2;
|
unsigned short value1, value2;
|
||||||
@@ -3252,13 +3057,10 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
|
|
||||||
assert(icmp1->icmp_type == 0 && icmp2->icmp_type == 0);
|
assert(icmp1->icmp_type == 0 && icmp2->icmp_type == 0);
|
||||||
|
|
||||||
/* Create the Avals */
|
hss->FP_TIcmp= new FingerTest(FingerPrintDef::IE, *o.reference_FPs->MatchPoints);
|
||||||
std::vector<struct AVal> *AVs = new std::vector<struct AVal>;
|
FingerTest &test = *hss->FP_TIcmp;
|
||||||
AVs->reserve(numtests);
|
|
||||||
|
|
||||||
AV.attribute = "R";
|
test.setAVal("R", "Y");
|
||||||
AV.value = "Y";
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* DFI test values:
|
/* DFI test values:
|
||||||
* Y. Both set DF;
|
* Y. Both set DF;
|
||||||
@@ -3266,52 +3068,42 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int
|
|||||||
* N. Both not set;
|
* N. Both not set;
|
||||||
* O. Other(both different with the sender, -_-b).
|
* O. Other(both different with the sender, -_-b).
|
||||||
*/
|
*/
|
||||||
AV.attribute = "DFI";
|
|
||||||
value1 = (ntohs(ip1->ip_off) & IP_DF);
|
value1 = (ntohs(ip1->ip_off) & IP_DF);
|
||||||
value2 = (ntohs(ip2->ip_off) & IP_DF);
|
value2 = (ntohs(ip2->ip_off) & IP_DF);
|
||||||
if (value1 && value2)
|
if (value1 && value2)
|
||||||
/* both set */
|
/* both set */
|
||||||
AV.value = "Y";
|
test.setAVal("DFI", "Y");
|
||||||
else if (value1 && !value2)
|
else if (value1 && !value2)
|
||||||
/* echo back */
|
/* echo back */
|
||||||
AV.value = "S";
|
test.setAVal("DFI", "S");
|
||||||
else if (!value1 && !value2)
|
else if (!value1 && !value2)
|
||||||
/* neither set */
|
/* neither set */
|
||||||
AV.value = "N";
|
test.setAVal("DFI", "N");
|
||||||
else
|
else
|
||||||
AV.value = "O";
|
test.setAVal("DFI", "O");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* TTL */
|
/* TTL */
|
||||||
|
|
||||||
AV.attribute = "T";
|
test.setAVal("T", hss->target->FPR->cp_hex(ip1->ip_ttl));
|
||||||
AV.value = hss->target->FPR->cp_hex(ip1->ip_ttl);
|
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
/* ICMP Code value. Test values:
|
/* ICMP Code value. Test values:
|
||||||
* [Value]. Both set Code to the same value [Value];
|
* [Value]. Both set Code to the same value [Value];
|
||||||
* S. Both use the Code that the sender uses;
|
* S. Both use the Code that the sender uses;
|
||||||
* O. Other.
|
* O. Other.
|
||||||
*/
|
*/
|
||||||
AV.attribute = "CD";
|
|
||||||
value1 = icmp1->icmp_code;
|
value1 = icmp1->icmp_code;
|
||||||
value2 = icmp2->icmp_code;
|
value2 = icmp2->icmp_code;
|
||||||
if (value1 == value2) {
|
if (value1 == value2) {
|
||||||
if (value1 == 0)
|
if (value1 == 0)
|
||||||
AV.value = "Z";
|
test.setAVal("CD", "Z");
|
||||||
else
|
else
|
||||||
AV.value = hss->target->FPR->cp_hex(value1);
|
test.setAVal("CD", hss->target->FPR->cp_hex(value1));
|
||||||
}
|
}
|
||||||
else if (value1 == 9 && value2 == 0)
|
else if (value1 == 9 && value2 == 0)
|
||||||
/* both the same as in the corresponding probe */
|
/* both the same as in the corresponding probe */
|
||||||
AV.value = "S";
|
test.setAVal("CD", "S");
|
||||||
else
|
else
|
||||||
AV.value = "O";
|
test.setAVal("CD", "O");
|
||||||
AVs->push_back(AV);
|
|
||||||
|
|
||||||
hss->FP_TIcmp= new FingerTest;
|
|
||||||
hss->FP_TIcmp->name = "IE";
|
|
||||||
hss->FP_TIcmp->results = AVs;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
42
osscan2.h
42
osscan2.h
@@ -71,8 +71,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include "timing.h"
|
#include "timing.h"
|
||||||
struct FingerPrint;
|
#include "osscan.h"
|
||||||
struct FingerTest;
|
|
||||||
class FingerPrintResultsIPv4;
|
class FingerPrintResultsIPv4;
|
||||||
class Target;
|
class Target;
|
||||||
|
|
||||||
@@ -81,8 +80,6 @@ class Target;
|
|||||||
* CONSTANT DEFINITIONS *
|
* CONSTANT DEFINITIONS *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#define NUM_FPTESTS 13
|
|
||||||
|
|
||||||
/* The number of tries we normally do. This may be increased if
|
/* The number of tries we normally do. This may be increased if
|
||||||
the target looks like a good candidate for fingerprint submission, or fewer
|
the target looks like a good candidate for fingerprint submission, or fewer
|
||||||
if the user gave the --max-os-tries option */
|
if the user gave the --max-os-tries option */
|
||||||
@@ -173,11 +170,6 @@ typedef enum OFProbeType {
|
|||||||
* FUNCTION PROTOTYPES *
|
* FUNCTION PROTOTYPES *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/* This is the primary OS detection function. If many Targets are
|
|
||||||
passed in (the threshold is based on timing level), they are
|
|
||||||
processed as smaller groups to improve accuracy */
|
|
||||||
void os_scan2(std::vector<Target *> &Targets);
|
|
||||||
|
|
||||||
int get_initial_ttl_guess(u8 ttl);
|
int get_initial_ttl_guess(u8 ttl);
|
||||||
|
|
||||||
int identify_sequence(int numSamples, u32 *ipid_diffs, int islocalhost, int allipideqz);
|
int identify_sequence(int numSamples, u32 *ipid_diffs, int islocalhost, int allipideqz);
|
||||||
@@ -303,22 +295,22 @@ class HostOsScanStats {
|
|||||||
* finally be passed to hs->target->FPR->FPs[x]. */
|
* finally be passed to hs->target->FPR->FPs[x]. */
|
||||||
FingerPrint *FP;
|
FingerPrint *FP;
|
||||||
FingerTest *FPtests[NUM_FPTESTS];
|
FingerTest *FPtests[NUM_FPTESTS];
|
||||||
#define FP_TSeq FPtests[0]
|
#define FP_TSeq FPtests[ID2INT(FingerPrintDef::SEQ)]
|
||||||
#define FP_TOps FPtests[1]
|
#define FP_TOps FPtests[ID2INT(FingerPrintDef::OPS)]
|
||||||
#define FP_TWin FPtests[2]
|
#define FP_TWin FPtests[ID2INT(FingerPrintDef::WIN)]
|
||||||
#define FP_TEcn FPtests[3]
|
#define FP_TEcn FPtests[ID2INT(FingerPrintDef::ECN)]
|
||||||
#define FP_T1_7_OFF 4
|
#define FP_T1_7_OFF ID2INT(FingerPrintDef::T1)
|
||||||
#define FP_T1 FPtests[4]
|
#define FP_T1 FPtests[ID2INT(FingerPrintDef::T1)]
|
||||||
#define FP_T2 FPtests[5]
|
#define FP_T2 FPtests[ID2INT(FingerPrintDef::T2)]
|
||||||
#define FP_T3 FPtests[6]
|
#define FP_T3 FPtests[ID2INT(FingerPrintDef::T3)]
|
||||||
#define FP_T4 FPtests[7]
|
#define FP_T4 FPtests[ID2INT(FingerPrintDef::T4)]
|
||||||
#define FP_T5 FPtests[8]
|
#define FP_T5 FPtests[ID2INT(FingerPrintDef::T5)]
|
||||||
#define FP_T6 FPtests[9]
|
#define FP_T6 FPtests[ID2INT(FingerPrintDef::T6)]
|
||||||
#define FP_T7 FPtests[10]
|
#define FP_T7 FPtests[ID2INT(FingerPrintDef::T7)]
|
||||||
#define FP_TUdp FPtests[11]
|
#define FP_TUdp FPtests[ID2INT(FingerPrintDef::U1)]
|
||||||
#define FP_TIcmp FPtests[12]
|
#define FP_TIcmp FPtests[ID2INT(FingerPrintDef::IE)]
|
||||||
struct AVal *TOps_AVs[6]; /* 6 AVs of TOps */
|
const char *TOps_AVs[6]; /* 6 AVs of TOps */
|
||||||
struct AVal *TWin_AVs[6]; /* 6 AVs of TWin */
|
const char *TWin_AVs[6]; /* 6 AVs of TWin */
|
||||||
|
|
||||||
/* The following are variables to store temporary results
|
/* The following are variables to store temporary results
|
||||||
* during the os fingerprinting process of this host. */
|
* during the os fingerprinting process of this host. */
|
||||||
|
|||||||
Reference in New Issue
Block a user