mirror of
https://github.com/nmap/nmap.git
synced 2025-12-24 00:19:01 +00:00
Zhao's rewritten and much-improved fingerfix (C this time rather than lame fingerfix.pl Perl hack
This commit is contained in:
669
scripts/fingerfix.cc
Normal file
669
scripts/fingerfix.cc
Normal file
@@ -0,0 +1,669 @@
|
||||
#include "nbase.h"
|
||||
#include "nmap.h"
|
||||
#include "osscan.h"
|
||||
#include "MACLookup.h"
|
||||
|
||||
// attribute value length
|
||||
#define AVLEN 128
|
||||
|
||||
void usage() {
|
||||
printf("Usage: fingerdiff\n"
|
||||
"(You will be prompted for the fingerprint data)\n\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int checkFP(char *FP) {
|
||||
char *p;
|
||||
char macbuf[16];
|
||||
u8 macprefix[3];
|
||||
char tmp;
|
||||
bool founderr = false;
|
||||
int i;
|
||||
|
||||
// SCAN
|
||||
p = strstr(FP, "SCAN(");
|
||||
if(!p) {
|
||||
founderr = true;
|
||||
printf("[WARN] SCAN line is missing");
|
||||
} else {
|
||||
// SCAN.G: whether the fingerprint is good
|
||||
p = strstr(FP, "%G=");
|
||||
if(!p) p = strstr(FP, "(G=");
|
||||
if(!p) {
|
||||
printf("[WARN] Attribute G is missing in SCAN line\n");
|
||||
founderr = true;
|
||||
} else {
|
||||
tmp = *(p+3);
|
||||
if(tmp != 'Y') {
|
||||
printf("[WARN] One fingerprint is not good\n");
|
||||
founderr = true;
|
||||
}
|
||||
}
|
||||
|
||||
// SCAN.M: mac prefix of the target.
|
||||
// if there is a MAC prefix, print the vendor name
|
||||
p = strstr(FP, "%M=");
|
||||
if(!p) p = strstr(FP, "(M=");
|
||||
if(p) {
|
||||
p = p + 3;
|
||||
for(i = 0; i < 6; i++) {
|
||||
if(!p[i] || !isxdigit(p[i])) {
|
||||
printf("[WARN] Invalid value (%s) occurs in SCAN.M\n", p);
|
||||
founderr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!founderr) {
|
||||
strncpy(macbuf, p, 6);
|
||||
i = strtol(macbuf, NULL, 16);
|
||||
macprefix[0] = i >> 16;
|
||||
macprefix[1] = (i >> 8) & 0xFF;
|
||||
macprefix[2] = i & 0xFF;
|
||||
printf("[INFO] Vendor Info: %s\n", MACPrefix2Corp(macprefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we validate that all elements are present */
|
||||
p = FP;
|
||||
if (!strstr(p, "SEQ(") || !strstr(p, "OPS(") || !strstr(p, "WIN(") ||
|
||||
!strstr(p, "ECN(") || !strstr(p, "T1(") || !strstr(p, "T2(") ||
|
||||
!strstr(p, "T3(") || !strstr(p, "T4(") || !strstr(p, "T5(") ||
|
||||
!strstr(p, "T6(") || !strstr(p, "T7(") || !strstr(p, "U1(") ||
|
||||
!strstr(p, "IE(")) {
|
||||
/* This ought to get my attention :) */
|
||||
founderr = true;
|
||||
printf("[WARN] Fingerprint is missing at least 1 element\n");
|
||||
}
|
||||
|
||||
if(founderr) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns -1 (or exits) for failure */
|
||||
static int readFP(FILE *filep, char *FP, int FPsz ) {
|
||||
char line[512];
|
||||
int linelen = 0;
|
||||
int lineno = 0;
|
||||
char *p, *q;
|
||||
char *oneFP;
|
||||
char *dst = FP;
|
||||
char tmp[16];
|
||||
int i;
|
||||
bool isInWrappedFP = false; // whether we are currently reading in a
|
||||
// wrapped fingerprint
|
||||
|
||||
if(FPsz < 50) return -1;
|
||||
FP[0] = '\0';
|
||||
|
||||
while((fgets(line, sizeof(line), filep))) {
|
||||
lineno++;
|
||||
linelen = strlen(line);
|
||||
p = line;
|
||||
if (*p == '\n' || *p == '.') {
|
||||
// end of input
|
||||
|
||||
if(isInWrappedFP) {
|
||||
// We have just completed reading in a wrapped fp. Because a
|
||||
// wrapped fp is submitted by user, so we check if there is a
|
||||
// SCAN line in it. If yes, look inside the scan line.
|
||||
*dst = '\0';
|
||||
checkFP(oneFP);
|
||||
isInWrappedFP = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while(*p && isspace(*p)) p++;
|
||||
if (*p == '#')
|
||||
continue; // skip the comment line
|
||||
|
||||
if (dst - FP + linelen >= FPsz - 5)
|
||||
fatal("[ERRO] Overflow!\n");
|
||||
|
||||
if(strncmp(p, "OS:", 3) == 0) {
|
||||
// the line is start with "OS:"
|
||||
if(!isInWrappedFP) {
|
||||
// just enter a wrapped fp area
|
||||
oneFP = dst;
|
||||
isInWrappedFP = true;
|
||||
}
|
||||
p += 3;
|
||||
while(*p != '\r' && *p != '\n') {
|
||||
*dst++ = toupper(*p);
|
||||
if(*p == ')') *dst++ = '\n';
|
||||
p++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// this line is not start with "OS:"
|
||||
if(isInWrappedFP) {
|
||||
// We have just completed reading in a wrapped fp. Because a
|
||||
// wrapped fp is submitted by user, so we check if there is a
|
||||
// SCAN line in it. If yes, look inside the scan line.
|
||||
*dst = '\0';
|
||||
checkFP(oneFP);
|
||||
isInWrappedFP = false;
|
||||
}
|
||||
|
||||
q = p; i = 0;
|
||||
while(q && *q && i<12)
|
||||
tmp[i++] = toupper(*q++);
|
||||
tmp[i] = '\0';
|
||||
if(strncmp(tmp, "FINGERPRINT", 11) == 0) {
|
||||
q = p + 11;
|
||||
while(*q && isspace(*q)) q++;
|
||||
if (*q) { // this fingeprint line is not empty
|
||||
strncpy(dst, "Fingerprint", 11);
|
||||
dst += 11;
|
||||
p += 11;
|
||||
while(*p) *dst++ = *p++;
|
||||
}
|
||||
continue;
|
||||
} else if(strncmp(tmp, "CLASS", 5) == 0) {
|
||||
q = p + 5;
|
||||
while(*q && isspace(*q)) q++;
|
||||
if (*q) {// this class line is not empty
|
||||
strncpy(dst, "Class", 5);
|
||||
dst += 5;
|
||||
p += 5;
|
||||
while(*p) *dst++ = *p++;
|
||||
}
|
||||
continue;
|
||||
} else if(strchr(p, '(')) {
|
||||
while(*p) *dst++ = toupper(*p++);
|
||||
} else {
|
||||
printf("[WARN] Skip bogus line: %s\n", p);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we validate that all elements are present. Though this maybe
|
||||
// redundant because we have checked it for those wrapped FPs, it
|
||||
// doesn't hurt to give a duplicated warning here.
|
||||
p = FP;
|
||||
if (!strstr(p, "SEQ(") || !strstr(p, "OPS(") || !strstr(p, "WIN(") ||
|
||||
!strstr(p, "ECN(") || !strstr(p, "T1(") || !strstr(p, "T2(") ||
|
||||
!strstr(p, "T3(") || !strstr(p, "T4(") || !strstr(p, "T5(") ||
|
||||
!strstr(p, "T6(") || !strstr(p, "T7(") || !strstr(p, "U1(") ||
|
||||
!strstr(p, "IE(")) {
|
||||
/* This ought to get my attention :) */
|
||||
printf("[WARN] Fingerprint is missing at least 1 element\n");
|
||||
}
|
||||
|
||||
if (dst - FP < 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
STR, DECNUM, HEXNUM
|
||||
} SortAs;
|
||||
|
||||
static void sort_and_merge(struct AVal *result, char values[][AVLEN], int num, SortAs sortas) {
|
||||
// sort and merge input values like 4,12,8 to 4|8|12. The sorting is
|
||||
// firstly based on their length, and secondly based on their ascii
|
||||
// order.
|
||||
assert(num > 0);
|
||||
|
||||
int i, j;
|
||||
char tmp[AVLEN];
|
||||
int offset;
|
||||
bool lt;
|
||||
unsigned int val1, val2;
|
||||
int base;
|
||||
|
||||
// sort
|
||||
for(i = 0; i < num; i++) {
|
||||
for(j = 1; j < num - i; j++) {
|
||||
lt = false;
|
||||
if(sortas == STR) {
|
||||
// sort as string
|
||||
// string with less length is regarded as "smaller"
|
||||
if((strlen(values[j-1]) > strlen(values[j])) ||
|
||||
(strlen(values[j-1]) == strlen(values[j]) && strcmp(values[j-1], values[j]) > 0)) {
|
||||
lt = true;
|
||||
}
|
||||
} else {
|
||||
// sort as number
|
||||
if(sortas == DECNUM) base = 10;
|
||||
else if(sortas == HEXNUM) base = 16;
|
||||
val1 = strtol(values[j-1], NULL, base);
|
||||
val2 = strtol(values[j], NULL, base);
|
||||
if(val1 > val2) lt = true;
|
||||
}
|
||||
|
||||
if(lt) {
|
||||
// printf("swap %s and %s\n", values[j-1], values[j]);
|
||||
strcpy(tmp, values[j-1]);
|
||||
strcpy(values[j-1], values[j]);
|
||||
strcpy(values[j], tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// merge.
|
||||
offset = 0;
|
||||
for(i = 0; i < num; i++) {
|
||||
if(i > 0 && strcmp(values[i], tmp) == 0) {
|
||||
// this is a duplicated value;
|
||||
continue;
|
||||
}
|
||||
strcpy(tmp, values[i]);
|
||||
offset += snprintf(result->value + offset, AVLEN - offset, "%s|", values[i]);
|
||||
if(offset >= AVLEN) {
|
||||
printf("[WARN] Attribute %s is too long and has been truncated\n", result->attribute);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result->value[offset-1] = '\0'; // remove the final '|'
|
||||
}
|
||||
|
||||
static void merge_gcd(struct AVal *result, char values[][AVLEN], int num) {
|
||||
// When fingerfix gets a GCD like 0x32, it changes it to "GCD=<67".
|
||||
// That seems kindof bogus. The GCD is only likely to be 0x32 or
|
||||
// (in rare cases by coincidence) a small multiple of that. So I
|
||||
// think it should give "GCD=32|64|96|C8|FA|12C". For the common
|
||||
// case of GCD=1, still saying GCD=<7 is desirable because that is
|
||||
// shorter than GCD=1|2|3|4|5|6 .
|
||||
assert(num > 0);
|
||||
|
||||
const unsigned int LIM = 7;
|
||||
int i, j;
|
||||
char *p, *q, *endptr;
|
||||
unsigned int val;
|
||||
unsigned int curlim = 0;
|
||||
bool haslim = false;
|
||||
int newValueNum = 0;
|
||||
char newValues[128][AVLEN];
|
||||
|
||||
// first let's find the limit
|
||||
for(i = 0; i < num; i++) {
|
||||
p = values[i];
|
||||
q = strchr(p, '<');
|
||||
if(q) {
|
||||
val = strtol(q + 1, &endptr, 16);
|
||||
if (q != p || *endptr) {
|
||||
printf("[WARN] Invalid value (%s) occurs in attribute SEQ.GCD\n", p);
|
||||
continue;
|
||||
}
|
||||
if(curlim < val) {
|
||||
curlim = val;
|
||||
haslim = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normally the limit should be the same with the LIM, since any limit
|
||||
// exist in the fingerprint is supposed to be generated by this
|
||||
// tool. Thus if it is not the case, print a warning.
|
||||
if(haslim && curlim != LIM) {
|
||||
printf("[WARN] Odd limit (%X) occurs in attribute SEQ.GCD", curlim);
|
||||
if(curlim < LIM) curlim = LIM;
|
||||
}
|
||||
|
||||
for(i = 0; i < num; i++) {
|
||||
p = values[i];
|
||||
q = strchr(p, '<');
|
||||
if(q) continue; // let's skip those limit strings
|
||||
val = strtol(p, &endptr, 16);
|
||||
if (*endptr) {
|
||||
printf("[WARN] Invalid value (%s) occurs in attribute SEQ.GCD\n", p);
|
||||
continue;
|
||||
} else if(val == 0) {
|
||||
printf("[WARN] Zero value occurs in attribute SEQ.GCD\n");
|
||||
}
|
||||
|
||||
if(haslim) {
|
||||
if(val <= curlim) continue;
|
||||
} else if(val <= LIM) {
|
||||
curlim = LIM;
|
||||
haslim = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
for(j = 1; j < 7; j++)
|
||||
snprintf(newValues[newValueNum++], AVLEN, "%X", val * j);
|
||||
}
|
||||
|
||||
if(newValueNum == 0 && haslim) {
|
||||
snprintf(result->value, AVLEN, "<%X", curlim);
|
||||
} else if(newValueNum > 0 && !haslim) {
|
||||
sort_and_merge(result, newValues, newValueNum, HEXNUM);
|
||||
} else if(newValues > 0 && haslim) {
|
||||
struct AVal semiresult;
|
||||
int offset;
|
||||
semiresult.attribute = "GCD";
|
||||
sort_and_merge(&semiresult, newValues, newValueNum, HEXNUM);
|
||||
// insert the limit string to the front of it
|
||||
offset = snprintf(result->value, AVLEN, "<%X|%s", curlim, semiresult.value);
|
||||
if(offset>=AVLEN) {
|
||||
printf("[WARN] SEQ.GCD is too long and has been truncated\n");
|
||||
}
|
||||
} else {
|
||||
result->value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void merge_sp_or_isr(struct AVal *result, char values[][AVLEN], int num) {
|
||||
// Fingerfix should expand elements based on observed deviation.
|
||||
// So if a fingerprint comes in with SP=0x9C (and that is the only
|
||||
// SEQ line), that means that all 3 Nmap tries had SP=0x9C and so it
|
||||
// may be OK to just use 0x9C in the reference fingerprint
|
||||
// generated, or maybe expand it by 1 like 0x9B-0x9D. But if the
|
||||
// fingerprint has 3 seq lines (which Nmap does when any elements in
|
||||
// it differ) and they show SP values of 0x9C, 0x84, and 0xA7, you
|
||||
// may want to handle them as: 1) You see 0x9C. Now your low and
|
||||
// high values are 0x9c 2) You see 0x84. This makes for a low of
|
||||
// 0x84 and a high of 0x9C you've seen. But you may want to double
|
||||
// the size of this new range, so it is now 0x78-0xA8. Note that
|
||||
// since your previous low and high values were equal, you expand in
|
||||
// both directions rather than just expanding in one direction. But
|
||||
// once you have developed a range, you'll start expanding only in
|
||||
// the direction of the outlying value. 3) You see 0xA7. This fits
|
||||
// into your range so you ignore it. 4) Suppose you then see 0xAA.
|
||||
// This is 3 higher than the top of your range, so you double that
|
||||
// and extend your upper range by 6 to 0x78-0xAD. It is important
|
||||
// to be careful not to keep expanding already-expanded values. So
|
||||
// if someone passes 0x78-0xAD in a reference FP to fingerfix, don't
|
||||
// double that range again. But if you then see 0x77, you would
|
||||
// change your range to 0x76-0xAD. This way we keep tight
|
||||
// fingerprints where the SP doesn't differ so much, but we avoid
|
||||
// having to constantly tweak fingerprints which differ
|
||||
// dramatically.
|
||||
assert(num > 0);
|
||||
int i;
|
||||
int low, high, val1, val2;
|
||||
char *p, *q, *r, buf[AVLEN];
|
||||
|
||||
result->value[0] = '\0';
|
||||
|
||||
for(i = 0; i < num; i++) {
|
||||
strncpy(buf, values[i], AVLEN);
|
||||
p = strchr(buf, '-');
|
||||
|
||||
if(p) {
|
||||
// an interval
|
||||
*p = '\0';
|
||||
val1 = (int)strtol(buf, &q, 16);
|
||||
val2 = (int)strtol(p+1, &r, 16);
|
||||
if(*q || *r || val1 >= val2) {
|
||||
printf("[WARN] Invalid value (%s) occurs in attribute SEQ.%s\n", values[i], result->attribute);
|
||||
return;
|
||||
}
|
||||
|
||||
// do not expand an interval
|
||||
if(i == 0) {
|
||||
low = val1;
|
||||
high = val2;
|
||||
} else {
|
||||
if(val1 < low) low = val1;
|
||||
if(val2 > high) high = val2;
|
||||
}
|
||||
} else {
|
||||
// a value
|
||||
val1 = (int)strtol(buf, &p, 16);
|
||||
if(*p) {
|
||||
printf("[WARN] Invalid value (%s) occurs in attribute SEQ.%s\n", values[i], result->attribute);
|
||||
return;
|
||||
}
|
||||
if(!val1) {
|
||||
// a zero sp/isr value, this should
|
||||
printf("[WARN] Zero value occurs in attribute SEQ.%s. A constant ISN sequence?\n", result->attribute);
|
||||
}
|
||||
if(i == 0) {
|
||||
low = high = val1;
|
||||
} else {
|
||||
if(low == high && val1 != low) {
|
||||
// expand it in both directions
|
||||
if(val1 < low) {
|
||||
low = val1 - (low - val1) / 2;
|
||||
high = high + (high - val1) / 2;
|
||||
} else {
|
||||
low = low - (val1 - low) / 2;
|
||||
high = high + (val1 - high) / 2;
|
||||
}
|
||||
if(low < 0) low = 0;
|
||||
} else if(val1 < low) {
|
||||
// expand in the left direction
|
||||
low = val1 - (low - val1);
|
||||
if(low < 0) low = 0;
|
||||
} else if(val1 > high) {
|
||||
// expand in the right direction
|
||||
high = val1 + (val1 - high);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(low == high && low == 0) {
|
||||
snprintf(result->value, AVLEN, "0");
|
||||
return;
|
||||
}
|
||||
|
||||
if(low == high) {
|
||||
// expanded it a little
|
||||
low = low - 1;
|
||||
if(low < 0) low = 0;
|
||||
high = high + 1;
|
||||
}
|
||||
|
||||
snprintf(result->value, AVLEN, "%X-%X", low, high);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FingerPrint *observedFP;
|
||||
FingerPrint *resultFP;
|
||||
FingerPrint *resultFPLine, *observedFPLine;
|
||||
char observedFPString[10240];
|
||||
char resultTemplate[] = {"SEQ(SP=%GCD=%ISR=%TI=%II=%SS=%TS=)\n"
|
||||
"OPS(O1=%O2=%O3=%O4=%O5=%O6=)\n"
|
||||
"WIN(W1=%W2=%W3=%W4=%W5=%W6=)\n"
|
||||
"ECN(R=%DF=%T=%TG=%W=%O=%CC=%Q=)\n"
|
||||
"T1(R=%DF=%T=%TG=%S=%A=%F=%RD=%Q=)\n"
|
||||
"T2(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"T3(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"T4(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"T5(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"T6(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"T7(R=%DF=%T=%TG=%W=%S=%A=%F=%O=%RD=%Q=)\n"
|
||||
"U1(DF=%T=%TG=%TOS=%IPL=%UN=%RIPL=%RID=%RIPCK=%RUCK=%RUL=%RUD=)\n"
|
||||
"IE(DFI=%T=%TG=%TOSI=%CD=%SI=%DLI=)\n"
|
||||
};
|
||||
|
||||
if (argc > 1)
|
||||
usage();
|
||||
|
||||
observedFPString[0] = '\0';
|
||||
printf("Enter the fingerprint(s) you want to fix, followed by a blank or single-dot line:\n");
|
||||
|
||||
if (readFP(stdin, observedFPString, sizeof(observedFPString)) == -1)
|
||||
fatal("[ERRO] Failed to read in supposed fingerprint from stdin\n");
|
||||
|
||||
observedFP = parse_single_fingerprint(observedFPString);
|
||||
if (!observedFP) fatal("[ERRO] failed to parse the observed fingerprint you entered\n");
|
||||
// printf("%s", fp2ascii(observedFP));
|
||||
|
||||
resultFP = parse_single_fingerprint(resultTemplate);
|
||||
// printf("%s", fp2ascii(resultFP));
|
||||
|
||||
bool foundline;
|
||||
struct AVal *resultAV, *observedAV, *tmpAV;
|
||||
char values[16][AVLEN];
|
||||
int avnum;
|
||||
int i;
|
||||
|
||||
for(resultFPLine = resultFP; resultFPLine; resultFPLine = resultFPLine->next) {
|
||||
// step 1:
|
||||
//
|
||||
// Check if this line is missing in the input fingerprint. If yes,
|
||||
// replace the result line with a R=N.
|
||||
foundline = false;
|
||||
for(observedFPLine = observedFP; observedFPLine; observedFPLine = observedFPLine->next) {
|
||||
if(observedFPLine->name && strcmp(resultFPLine->name, observedFPLine->name) == 0) {
|
||||
// Found the corresponding line. If it doesn't begin with a
|
||||
// R=N, then we take it as a good line.
|
||||
if(observedFPLine->results &&
|
||||
!(strcmp(observedFPLine->results->attribute, "R") == 0 &&
|
||||
strcmp(observedFPLine->results->value, "N") == 0)) {
|
||||
foundline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundline) {
|
||||
// replace the fingerprint line with a R=N
|
||||
free(resultFPLine->results);
|
||||
tmpAV = (struct AVal *) safe_zalloc(sizeof(struct AVal));
|
||||
tmpAV->attribute = "R";
|
||||
strcpy(tmpAV->value, "N");
|
||||
resultFPLine->results = tmpAV;
|
||||
continue;
|
||||
}
|
||||
|
||||
// step 2:
|
||||
//
|
||||
// For each AVal of this fingerprint line, merge all the
|
||||
// counterpart values appeared in the input fingerprint.
|
||||
for(resultAV = resultFPLine->results; resultAV; resultAV = resultAV->next) {
|
||||
avnum = 0;
|
||||
for(observedFPLine = observedFP; observedFPLine; observedFPLine = observedFPLine->next) {
|
||||
if(strcmp(resultFPLine->name, observedFPLine->name) == 0) {
|
||||
for(observedAV = observedFPLine->results; observedAV; observedAV = observedAV->next) {
|
||||
if(strcmp(resultAV->attribute, observedAV->attribute) == 0) {
|
||||
// check if we have stored the same attribute value if
|
||||
// not, store it
|
||||
bool stored;
|
||||
char *p, *q;
|
||||
p = observedAV->value;
|
||||
while(p && *p) {
|
||||
stored = false;
|
||||
q = strchr(p, '|');
|
||||
if(q) *q = '\0';
|
||||
for(i = 0; i < avnum; i++) {
|
||||
if(strcmp(values[i], p) == 0) {
|
||||
stored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!stored) {
|
||||
strcpy(values[avnum++], p);
|
||||
}
|
||||
if(q) p = q + 1;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(avnum == 0) {
|
||||
// no value for this attribute, now handle the next attribute
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we get all the values for this attribute, it's time to
|
||||
// merge them. let's first handle some special attributes.
|
||||
if(strcmp(resultFPLine->name, "SEQ") == 0 && strcmp(resultAV->attribute, "GCD") == 0) {
|
||||
// SEQ.GCD
|
||||
merge_gcd(resultAV, values, avnum);
|
||||
} else if(strcmp(resultFPLine->name, "SEQ") == 0 &&
|
||||
(strcmp(resultAV->attribute, "SP") == 0 || strcmp(resultAV->attribute, "ISR") == 0)) {
|
||||
// SEQ.SP or SEQ.ISR
|
||||
merge_sp_or_isr(resultAV, values, avnum);
|
||||
} else {
|
||||
// common merge
|
||||
sort_and_merge(resultAV, values, avnum, STR);
|
||||
}
|
||||
}
|
||||
|
||||
// step 3:
|
||||
// handle some special cases:
|
||||
// o remove SEQ.SS if it is null
|
||||
// o make up the TTL and TTL guess stuff
|
||||
struct AVal *av1, *av2;
|
||||
|
||||
// remove SEQ.SS
|
||||
if(strcmp(resultFPLine->name, "SEQ") == 0) {
|
||||
av1 = resultFPLine->results;
|
||||
while(av1) {
|
||||
if(strcmp(av1->attribute, "SS") == 0 && strlen(av1->value) == 0) {
|
||||
if(av1 == resultFPLine->results) {
|
||||
resultFPLine->results = av1->next;
|
||||
break;
|
||||
} else {
|
||||
av2->next = av1->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
av2 = av1;
|
||||
av1 = av1->next;
|
||||
}
|
||||
}
|
||||
|
||||
// TTL and TTL Guess
|
||||
av1 = NULL;
|
||||
av2 = NULL;
|
||||
if(strcmp(resultFPLine->name, "ECN") == 0 ||
|
||||
strcmp(resultFPLine->name, "T1") == 0 ||
|
||||
strcmp(resultFPLine->name, "T2") == 0 ||
|
||||
strcmp(resultFPLine->name, "T3") == 0 ||
|
||||
strcmp(resultFPLine->name, "T4") == 0 ||
|
||||
strcmp(resultFPLine->name, "T5") == 0 ||
|
||||
strcmp(resultFPLine->name, "T6") == 0 ||
|
||||
strcmp(resultFPLine->name, "T7") == 0 ||
|
||||
strcmp(resultFPLine->name, "U1") == 0 ||
|
||||
strcmp(resultFPLine->name, "IE") == 0) {
|
||||
for(tmpAV = resultFPLine->results; tmpAV; tmpAV = tmpAV->next ) {
|
||||
if(strcmp(tmpAV->attribute, "T") == 0) {
|
||||
av1 = tmpAV;
|
||||
} else if(strcmp(tmpAV->attribute, "TG") == 0) {
|
||||
av2 = tmpAV;
|
||||
}
|
||||
}
|
||||
|
||||
assert(av1&&av2);
|
||||
if(strlen(av1->value) == 0 && strlen(av2->value) > 0) {
|
||||
strcpy(av1->value, av2->value);
|
||||
} else if(strlen(av2->value) == 0 && strlen(av1->value) > 0) {
|
||||
strcpy(av2->value, av1->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// whew, we finally complete the job, now spit it out.
|
||||
printf("\nADJUSTED FINGERPRINT:\n");
|
||||
|
||||
// OS Name
|
||||
if(observedFP->OS_name) {
|
||||
printf("Fingerprint %s\n", observedFP->OS_name);
|
||||
} else {
|
||||
// print an empty fingerprint
|
||||
printf("Fingerprint\n");
|
||||
}
|
||||
|
||||
// Class
|
||||
if(observedFP->num_OS_Classifications > 0) {
|
||||
for(i = 0; i<observedFP->num_OS_Classifications; i++) {
|
||||
printf("Class %s | %s |",
|
||||
observedFP->OS_class[i].OS_Vendor,
|
||||
observedFP->OS_class[i].OS_Family);
|
||||
if(observedFP->OS_class[i].OS_Generation) {
|
||||
printf(" %s |", observedFP->OS_class[i].OS_Generation);
|
||||
} else {
|
||||
printf("|");
|
||||
}
|
||||
printf(" %s\n", observedFP->OS_class[i].Device_Type);
|
||||
}
|
||||
} else {
|
||||
// print a empty class line
|
||||
printf("Class\n");
|
||||
}
|
||||
|
||||
// Fingerprint
|
||||
printf("%s", fp2ascii(resultFP));
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user