Branch data Line data Source code
1 : : // $Id: OSFinger.cc 5857 2008-06-26 23:00:03Z vern $
2 : :
3 : : /*
4 : : Taken with permission from:
5 : :
6 : : p0f - passive OS fingerprinting (GNU LESSER GENERAL PUBLIC LICENSE)
7 : : -------------------------------------------------------------------
8 : :
9 : : "If you sit down at a poker game and don't see a sucker,
10 : : get up. You're the sucker."
11 : :
12 : : (C) Copyright 2000-2003 by Michal Zalewski <lcamtuf@coredump.cx>
13 : : */
14 : :
15 : : // To make it easier to upgrade this file to newer releases of p0f,
16 : : // it remains in the coding style used by p0f rather than Bro.
17 : :
18 : : #include "OSFinger.h"
19 : : #include "net_util.h"
20 : : #include "util.h"
21 : : #include "Var.h"
22 : : #include <stdlib.h>
23 : : #include <stdio.h>
24 : : #include <ctype.h>
25 : :
26 : :
27 : 0 : void int_delete_func(void* v)
28 : : {
29 : 0 : delete (int*) v;
30 : 0 : }
31 : :
32 : :
33 : : // Initializes data structures for fingerprinting in the given mode.
34 : 0 : OSFingerprint::OSFingerprint(FingerprintMode arg_mode)
35 : : {
36 : 0 : err = 0;
37 : 0 : mode = arg_mode;
38 : :
39 : 0 : sigcnt=gencnt=0;
40 : 0 : problems=0;
41 : : char* fname;
42 : :
43 : 0 : memset(sig, 0, sizeof(struct fp_entry)*MAXSIGS);
44 : 0 : memset(bh, 0, sizeof(struct fp_entry*)*OSHSIZE);
45 : :
46 : 0 : os_matches.SetDeleteFunc(int_delete_func);
47 : :
48 [ # # # # ]: 0 : if (mode == SYN_FINGERPRINT_MODE)
49 : : {
50 : 0 : fname = copy_string(internal_val("passive_fingerprint_file")->AsString()->CheckString());
51 : 0 : load_config(fname);
52 [ # # ][ # # ]: 0 : delete [] fname;
53 : : }
54 [ # # ][ # # ]: 0 : else if (mode == SYN_ACK_FINGERPRINT_MODE)
55 : : {//not yet supported
56 : 0 : load_config("p0fsynack.sig");
57 : : }
58 [ # # ][ # # ]: 0 : else if (mode == RST_FINGERPRINT_MODE)
59 : : {//not yet supported
60 : 0 : load_config("p0frst.sig");
61 : : }
62 : : else
63 : : {
64 : 0 : Error("OS fingerprinting: unknown mode!");
65 : : }
66 : 0 : }
67 : :
68 : 0 : bool OSFingerprint::CacheMatch(uint32 addr, int id)
69 : : {
70 : 0 : HashKey key = HashKey(&addr, 1);
71 : 0 : int* pid = new int;
72 : 0 : *pid=id;
73 : 0 : int* prev = os_matches.Insert(&key, pid);
74 [ # # # # ]: 0 : bool ret = (prev ? *prev != id : 1);
75 [ # # ]: 0 : if (prev)
76 : 0 : delete prev;
77 : 0 : return ret;
78 : : }
79 : :
80 : :
81 : : // Determines whether the signature file had any collisions.
82 : 0 : void OSFingerprint::collide(uint32 id)
83 : : {
84 : : uint32 i,j;
85 : : uint32 cur;
86 : :
87 [ # # ][ # # ]: 0 : if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30)
[ # # ]
88 : : {
89 : 0 : problems=1;
90 : : warn(fmt("OS fingerprinting: [!] Unusual TTL (%d) for signature '%s %s' (line %d).",
91 : 0 : sig[id].ttl,sig[id].os,sig[id].desc,sig[id].line));
92 : : }
93 : :
94 [ # # ]: 0 : for (i=0;i<id;i++)
95 : : {
96 [ # # ][ # # ]: 0 : if (!strcmp(sig[i].os,sig[id].os) &&
97 : : !strcmp(sig[i].desc,sig[id].desc)) {
98 : 0 : problems=1;
99 : : warn(fmt("OS fingerprinting: [!] Duplicate signature name: '%s %s' (line %d and %d).",
100 : 0 : sig[i].os,sig[i].desc,sig[i].line,sig[id].line));
101 : : }
102 : :
103 : : /* If TTLs are sufficiently away from each other, the risk of
104 : : a collision is lower. */
105 [ # # ]: 0 : if (abs((int)sig[id].ttl - (int)sig[i].ttl) > 25) continue;
106 : :
107 [ # # ]: 0 : if (sig[id].df ^ sig[i].df) continue;
108 [ # # ]: 0 : if (sig[id].zero_stamp ^ sig[i].zero_stamp) continue;
109 : :
110 : : /* Zero means >= PACKET_BIG */
111 [ # # ][ # # ]: 0 : if (sig[id].size) { if (sig[id].size ^ sig[i].size) continue; }
112 [ # # ]: 0 : else if (sig[i].size < PACKET_BIG) continue;
113 : :
114 [ # # ]: 0 : if (sig[id].optcnt ^ sig[i].optcnt) continue;
115 [ # # ]: 0 : if (sig[id].quirks ^ sig[i].quirks) continue;
116 : :
117 [ # # # # : 0 : switch (sig[id].wsize_mod) {
# ]
118 : :
119 : : case 0: /* Current: const */
120 : :
121 : 0 : cur=sig[id].wsize;
122 : :
123 : 0 : do_const:
124 : :
125 [ # # # # : 0 : switch (sig[i].wsize_mod) {
# ]
126 : :
127 : : case 0: /* Previous is also const */
128 : :
129 : : /* A problem if values match */
130 [ # # ]: 0 : if (cur ^ sig[i].wsize) continue;
131 : 0 : break;
132 : :
133 : : case MOD_CONST: /* Current: const, prev: modulo (or *) */
134 : :
135 : : /* A problem if current value is a multiple of that modulo */
136 [ # # ]: 0 : if (cur % sig[i].wsize) continue;
137 : 0 : break;
138 : :
139 : : case MOD_MSS: /* Current: const, prev: mod MSS */
140 : :
141 [ # # ][ # # ]: 0 : if (sig[i].mss_mod || sig[i].wsize *
[ # # ]
142 : : (sig[i].mss ? sig[i].mss : 1460 ) != (int) cur)
143 : 0 : continue;
144 : :
145 : 0 : break;
146 : :
147 : : case MOD_MTU: /* Current: const, prev: mod MTU */
148 : :
149 [ # # ][ # # ]: 0 : if (sig[i].mss_mod || sig[i].wsize * (
[ # # ]
150 : : (sig[i].mss ? sig[i].mss : 1460 )+40) != (int) cur)
151 : 0 : continue;
152 : :
153 : : break;
154 : :
155 : : }
156 : :
157 : 0 : break;
158 : :
159 : : case 1: /* Current signature is modulo something */
160 : :
161 : : /* A problem only if this modulo is a multiple of the
162 : : previous modulo */
163 : :
164 [ # # ]: 0 : if (sig[i].wsize_mod != MOD_CONST) continue;
165 [ # # ]: 0 : if (sig[id].wsize % sig[i].wsize) continue;
166 : :
167 : 0 : break;
168 : :
169 : : case MOD_MSS: /* Current is modulo MSS */
170 : :
171 : : /* There's likely a problem only if the previous one is close
172 : : to '*'; we do not check known MTUs, because this particular
173 : : signature can be made with some uncommon MTUs in mind. The
174 : : problem would also appear if current signature has a fixed
175 : : MSS. */
176 : :
177 [ # # ][ # # ]: 0 : if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
178 [ # # ]: 0 : if (!sig[id].mss_mod) {
179 [ # # ]: 0 : cur = (sig[id].mss ? sig[id].mss : 1460 ) * sig[id].wsize;
180 : 0 : goto do_const;
181 : : }
182 : 0 : continue;
183 : : }
184 : :
185 : 0 : break;
186 : :
187 : : case MOD_MTU: /* Current is modulo MTU */
188 : :
189 [ # # ][ # # ]: 0 : if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize <= 8) {
190 [ # # ]: 0 : if (!sig[id].mss_mod) {
191 [ # # ]: 0 : cur = ( (sig[id].mss ? sig[id].mss : 1460 ) +40) * sig[id].wsize;
192 : 0 : goto do_const;
193 : : }
194 : 0 : continue;
195 : : }
196 : :
197 : : break;
198 : :
199 : : }
200 : :
201 : : /* Same for wsc */
202 [ # # # ]: 0 : switch (sig[id].wsc_mod) {
203 : :
204 : : case 0: /* Current: const */
205 : :
206 : 0 : cur=sig[id].wsc;
207 : :
208 [ # # # ]: 0 : switch (sig[i].wsc_mod) {
209 : :
210 : : case 0: /* Previous is also const */
211 : :
212 : : /* A problem if values match */
213 [ # # ]: 0 : if (cur ^ sig[i].wsc) continue;
214 : 0 : break;
215 : :
216 : : case 1: /* Current: const, prev: modulo (or *) */
217 : :
218 : : /* A problem if current value is a multiple of that modulo */
219 [ # # ]: 0 : if (cur % sig[i].wsc) continue;
220 : : break;
221 : :
222 : : }
223 : :
224 : 0 : break;
225 : :
226 : : case MOD_CONST: /* Current signature is modulo something */
227 : :
228 : : /* A problem only if this modulo is a multiple of the
229 : : previous modulo */
230 : :
231 [ # # ]: 0 : if (!sig[i].wsc_mod) continue;
232 [ # # ]: 0 : if (sig[id].wsc % sig[i].wsc) continue;
233 : :
234 : : break;
235 : :
236 : : }
237 : :
238 : : /* Same for mss */
239 [ # # # ]: 0 : switch (sig[id].mss_mod) {
240 : :
241 : : case 0: /* Current: const */
242 : :
243 : 0 : cur=sig[id].mss;
244 : :
245 [ # # # ]: 0 : switch (sig[i].mss_mod) {
246 : :
247 : : case 0: /* Previous is also const */
248 : :
249 : : /* A problem if values match */
250 [ # # ]: 0 : if (cur ^ sig[i].mss) continue;
251 : 0 : break;
252 : :
253 : : case 1: /* Current: const, prev: modulo (or *) */
254 : :
255 : : /* A problem if current value is a multiple of that modulo */
256 [ # # ]: 0 : if (cur % sig[i].mss) continue;
257 : : break;
258 : :
259 : : }
260 : :
261 : 0 : break;
262 : :
263 : : case MOD_CONST: /* Current signature is modulo something */
264 : :
265 : : /* A problem only if this modulo is a multiple of the
266 : : previous modulo */
267 : :
268 [ # # ]: 0 : if (!sig[i].mss_mod) continue;
269 [ # # ][ # # ]: 0 : if ((sig[id].mss ? sig[id].mss : 1460 ) %
[ # # ]
270 : 0 : (sig[i].mss ? sig[i].mss : 1460 )) continue;
271 : :
272 : : break;
273 : :
274 : : }
275 : :
276 : : /* Now check option sequence */
277 : :
278 [ # # ]: 0 : for (j=0;j<sig[id].optcnt;j++)
279 [ # # ]: 0 : if (sig[id].opt[j] ^ sig[i].opt[j]) goto reloop;
280 : :
281 : 0 : problems=1;
282 : : warn(fmt("OS fingerprinting: [!] Signature '%s %s' (line %d)\n"
283 : : " is already covered by '%s %s' (line %d).",
284 : : sig[id].os,sig[id].desc,sig[id].line,sig[i].os,sig[i].desc,
285 : 0 : sig[i].line));
286 : :
287 : 0 : reloop:
288 : : ;
289 : : }
290 : 0 : }
291 : :
292 : : // Loads a given file into to classes data structures.
293 : 0 : void OSFingerprint::load_config(const char* file)
294 : : {
295 : 0 : uint32 ln=0;
296 : : char buf[MAXLINE];
297 : : char* p;
298 : 0 : FILE* c = search_for_file( file, "osf", 0);
299 : :
300 [ # # ]: 0 : if (!c)
301 : : {
302 : 0 : Error("Can't open OS passive fingerprinting signature file", file);
303 : 0 : return;
304 : : }
305 : 0 : sigcnt=0; //every time we read config we reset it to 0;
306 [ # # ]: 0 : while ((p=fgets(buf,sizeof(buf),c)))
307 : : {
308 : : uint32 l;
309 : :
310 : : char obuf[MAXLINE],genre[MAXLINE],desc[MAXLINE],quirks[MAXLINE];
311 : : char w[MAXLINE],sb[MAXLINE];
312 : 0 : char* gptr = genre;
313 : : uint32 t,d,s;
314 : : struct fp_entry* e;
315 : :
316 : 0 : ln++;
317 : :
318 : : /* Remove leading and trailing blanks */
319 [ # # ]: 0 : while (isspace(*p)) p++;
320 : 0 : l=strlen(p);
321 [ # # ][ # # ]: 0 : while (l && isspace(*(p+l-1))) *(p+(l--)-1)=0;
322 : :
323 : : /* Skip empty lines and comments */
324 [ # # ]: 0 : if (!l) continue;
325 [ # # ]: 0 : if (*p == '#') continue;
326 : :
327 [ # # ]: 0 : if (sscanf(p,"%[0-9%*()ST]:%d:%d:%[0-9()*]:%[^:]:%[^ :]:%[^:]:%[^:]",
328 : : w, &t,&d,sb, obuf, quirks,genre,desc) != 8)
329 : 0 : Error("OS fingerprinting: Syntax error in p0f signature config line %d.\n",(uint32)ln);
330 : :
331 : 0 : gptr = genre;
332 : :
333 [ # # ]: 0 : if (*sb != '*') s = atoi(sb); else s = 0;
334 : :
335 : 0 : reparse_ptr:
336 : :
337 [ # # # # : 0 : switch (*gptr)
# ]
338 : : {
339 : 0 : case '-': sig[sigcnt].userland = 1; gptr++; goto reparse_ptr;
340 : 0 : case '*': sig[sigcnt].no_detail = 1; gptr++; goto reparse_ptr;
341 : 0 : case '@': sig[sigcnt].generic = 1; gptr++; gencnt++; goto reparse_ptr;
342 : 0 : case 0: Error("OS fingerprinting: Empty OS genre in line",(uint32)ln);
343 : : }
344 : :
345 : 0 : sig[sigcnt].os = strdup(gptr);
346 : 0 : sig[sigcnt].desc = strdup(desc);
347 : 0 : sig[sigcnt].ttl = t;
348 : 0 : sig[sigcnt].size = s;
349 : 0 : sig[sigcnt].df = d;
350 : :
351 [ # # ]: 0 : if (w[0] == '*')
352 : : {
353 : 0 : sig[sigcnt].wsize = 1;
354 : 0 : sig[sigcnt].wsize_mod = MOD_CONST;
355 : : }
356 [ # # ]: 0 : else if (tolower(w[0]) == 's')
357 : : {
358 : 0 : sig[sigcnt].wsize_mod = MOD_MSS;
359 [ # # ]: 0 : if (!isdigit(*(w+1)))
360 : 0 : Error("OS fingerprinting: Bad Snn value in WSS in line",(uint32)ln);
361 : 0 : sig[sigcnt].wsize = atoi(w+1);
362 : : }
363 [ # # ]: 0 : else if (tolower(w[0]) == 't')
364 : : {
365 : 0 : sig[sigcnt].wsize_mod = MOD_MTU;
366 [ # # ]: 0 : if (!isdigit(*(w+1)))
367 : 0 : Error("OS fingerprinting: Bad Tnn value in WSS in line",(uint32)ln);
368 : 0 : sig[sigcnt].wsize = atoi(w+1);
369 : : }
370 [ # # ]: 0 : else if (w[0] == '%')
371 : : {
372 [ # # ]: 0 : if (!(sig[sigcnt].wsize = atoi(w+1)))
373 : 0 : Error("OS fingerprinting: Null modulo for window size in config line",(uint32)ln);
374 : 0 : sig[sigcnt].wsize_mod = MOD_CONST;
375 : : }
376 : : else
377 : 0 : sig[sigcnt].wsize = atoi(w);
378 : :
379 : : /* Now let's parse options */
380 : :
381 : 0 : p=obuf;
382 : :
383 : 0 : sig[sigcnt].zero_stamp = 1;
384 : :
385 [ # # ]: 0 : if (*p=='.') p++;
386 : :
387 [ # # ]: 0 : while (*p)
388 : : {
389 : 0 : uint8 optcnt = sig[sigcnt].optcnt;
390 [ # # # # # : 0 : switch (tolower(*p))
# # # ]
391 : : {
392 : 0 : case 'n': sig[sigcnt].opt[optcnt] = TCPOPT_NOP;
393 : 0 : break;
394 : :
395 : 0 : case 'e': sig[sigcnt].opt[optcnt] = TCPOPT_EOL;
396 [ # # ]: 0 : if (*(p+1))
397 : 0 : Error("OS fingerprinting: EOL not the last option, line",(uint32)ln);
398 : 0 : break;
399 : :
400 : 0 : case 's': sig[sigcnt].opt[optcnt] = TCPOPT_SACK_PERMITTED;
401 : 0 : break;
402 : :
403 : 0 : case 't': sig[sigcnt].opt[optcnt] = TCPOPT_TIMESTAMP;
404 [ # # ]: 0 : if (*(p+1)!='0')
405 : : {
406 : 0 : sig[sigcnt].zero_stamp=0;
407 [ # # ]: 0 : if (isdigit(*(p+1)))
408 : 0 : Error("OS fingerprinting: Bogus Tstamp specification in line",(uint32)ln);
409 : : }
410 : 0 : break;
411 : :
412 : 0 : case 'w': sig[sigcnt].opt[optcnt] = TCPOPT_WINDOW;
413 [ # # ]: 0 : if (p[1] == '*')
414 : : {
415 : 0 : sig[sigcnt].wsc = 1;
416 : 0 : sig[sigcnt].wsc_mod = MOD_CONST;
417 : : }
418 [ # # ]: 0 : else if (p[1] == '%')
419 : : {
420 [ # # ]: 0 : if (!(sig[sigcnt].wsc = atoi(p+2)))
421 : 0 : Error("OS fingerprinting: Null modulo for wscale in config line",(uint32)ln);
422 : 0 : sig[sigcnt].wsc_mod = MOD_CONST;
423 : : }
424 [ # # ]: 0 : else if (!isdigit(*(p+1)))
425 : 0 : Error("OS fingerprinting: Incorrect W value in line",(uint32)ln);
426 : 0 : else sig[sigcnt].wsc = atoi(p+1);
427 : 0 : break;
428 : :
429 : 0 : case 'm': sig[sigcnt].opt[optcnt] = TCPOPT_MAXSEG;
430 [ # # ]: 0 : if (p[1] == '*')
431 : : {
432 : 0 : sig[sigcnt].mss = 1;
433 : 0 : sig[sigcnt].mss_mod = MOD_CONST;
434 : : }
435 [ # # ]: 0 : else if (p[1] == '%')
436 : : {
437 [ # # ]: 0 : if (!(sig[sigcnt].mss = atoi(p+2)))
438 : 0 : Error("OS fingerprinting: Null modulo for MSS in config line",(uint32)ln);
439 : 0 : sig[sigcnt].mss_mod = MOD_CONST;
440 : : }
441 [ # # ]: 0 : else if (!isdigit(*(p+1)))
442 : 0 : Error("OS fingerprinting: Incorrect M value in line",(uint32)ln);
443 : 0 : else sig[sigcnt].mss = atoi(p+1);
444 : 0 : break;
445 : :
446 : : /* Yuck! */
447 [ # # ]: 0 : case '?': if (!isdigit(*(p+1)))
448 : 0 : Error("OS fingerprinting: Bogus ?nn value in line",(uint32)ln);
449 : 0 : else sig[sigcnt].opt[optcnt] = atoi(p+1);
450 : 0 : break;
451 : :
452 : 0 : default: Error("OS fingerprinting: Unknown TCP option in config line",(uint32)ln);
453 : : }
454 : :
455 [ # # ]: 0 : if (++sig[sigcnt].optcnt >= MAXOPT)
456 : 0 : Error("OS fingerprinting: Too many TCP options specified in config line",(uint32)ln);
457 : :
458 : : /* Skip separators */
459 [ # # ][ # # ]: 0 : do { p++; } while (*p && !isalpha(*p) && *p != '?');
[ # # ]
460 : :
461 : : }
462 : :
463 : 0 : sig[sigcnt].line = ln;
464 : :
465 : 0 : p = quirks;
466 : :
467 [ # # ]: 0 : while (*p)
468 [ # # # # # : 0 : switch (toupper(*(p++)))
# # # # #
# # # # #
# ]
469 : : {
470 : : case 'E':
471 : 0 : Error("OS fingerprinting: Quirk 'E' is obsolete. Remove it, append E to the options. Line",(uint32)ln);
472 : :
473 : : case 'K':
474 [ # # ]: 0 : if ( mode != RST_FINGERPRINT_MODE )
475 : 0 : Error("OS fingerprinting: Quirk 'K' is valid only in RST+ (-R) mode (wrong config file?). Line",(uint32)ln);
476 : 0 : sig[sigcnt].quirks |= QUIRK_RSTACK;
477 : 0 : break;
478 : :
479 : 0 : case 'Q': sig[sigcnt].quirks |= QUIRK_SEQEQ; break;
480 : 0 : case '0': sig[sigcnt].quirks |= QUIRK_SEQ0; break;
481 : 0 : case 'P': sig[sigcnt].quirks |= QUIRK_PAST; break;
482 : 0 : case 'Z': sig[sigcnt].quirks |= QUIRK_ZEROID; break;
483 : 0 : case 'I': sig[sigcnt].quirks |= QUIRK_IPOPT; break;
484 : 0 : case 'U': sig[sigcnt].quirks |= QUIRK_URG; break;
485 : 0 : case 'X': sig[sigcnt].quirks |= QUIRK_X2; break;
486 : 0 : case 'A': sig[sigcnt].quirks |= QUIRK_ACK; break;
487 : 0 : case 'T': sig[sigcnt].quirks |= QUIRK_T2; break;
488 : 0 : case 'F': sig[sigcnt].quirks |= QUIRK_FLAGS; break;
489 : 0 : case 'D': sig[sigcnt].quirks |= QUIRK_DATA; break;
490 : 0 : case '!': sig[sigcnt].quirks |= QUIRK_BROKEN; break;
491 : 0 : case '.': break;
492 : 0 : default: Error("OS fingerprinting: Bad quirk in line",(uint32)ln);
493 : : }
494 : :
495 : 0 : e = bh[SIGHASH(s,sig[sigcnt].optcnt,sig[sigcnt].quirks,d)];
496 : :
497 [ # # ]: 0 : if (!e)
498 : : {
499 : 0 : bh[SIGHASH(s,sig[sigcnt].optcnt,sig[sigcnt].quirks,d)] = &sig[sigcnt];
500 : : }
501 : : else
502 : : {
503 [ # # ]: 0 : while (e->next) e = e->next;
504 : 0 : e->next = &sig[sigcnt];
505 : : }
506 : :
507 : 0 : collide(sigcnt);
508 [ # # ]: 0 : if (++sigcnt >= MAXSIGS)
509 : 0 : Error("OS fingerprinting: Maximum signature count exceeded.\n");
510 : :
511 : : }
512 : :
513 : 0 : fclose(c);
514 : :
515 [ # # ]: 0 : if (!sigcnt)
516 : 0 : Error("OS fingerprinting: no signatures loaded from config file.");
517 : :
518 : : }
519 : :
520 : : // Does the actual match between the packet and the signature database.
521 : : // Modifies retval and contains OS Type and other useful information.
522 : : // Returns config-file line of the matching signature as id.
523 : : int OSFingerprint::FindMatch(struct os_type* retval, uint16 tot,uint8 df,
524 : : uint8 ttl,uint16 wss,uint8 ocnt,uint8* op,
525 : : uint16 mss,uint8 wsc,uint32 tstamp,
526 : 0 : uint32 quirks,uint8 ecn) const
527 : : {
528 : : uint32 j; //used for counter in loops
529 : : struct fp_entry* p;
530 : 0 : uint8 orig_df = df;
531 : :
532 : 0 : struct fp_entry* fuzzy = 0;
533 : 0 : uint8 fuzzy_now = 0;
534 : 0 : int id = 0; //return value: 0 indicates no match.
535 : :
536 : 0 : retval->os="UNKNOWN";
537 : 0 : retval->desc=NULL;
538 : 0 : retval->gadgets=0;
539 : 0 : retval->match=0;
540 : 0 : retval->uptime=0;
541 : :
542 : 0 : re_lookup:
543 : :
544 : 0 : p = bh[SIGHASH(tot,ocnt,quirks,df)];
545 : :
546 [ # # ]: 0 : while (p)
547 : : {
548 : : /* Cheap and specific checks first... */
549 : : /* psize set to zero means >= PACKET_BIG */
550 [ # # ][ # # ]: 0 : if (p->size) { if (tot ^ p->size) { p = p->next; continue; } }
551 [ # # ]: 0 : else if (tot < PACKET_BIG) { p = p->next; continue; }
552 : :
553 [ # # ]: 0 : if (ocnt ^ p->optcnt) { p = p->next; continue; }
554 : :
555 [ # # ]: 0 : if (p->zero_stamp ^ (!tstamp)) { p = p->next; continue; }
556 [ # # ]: 0 : if (p->df ^ df) { p = p->next; continue; }
557 [ # # ]: 0 : if (p->quirks ^ quirks) { p = p->next; continue; }
558 : :
559 : : /* Check MSS and WSCALE... */
560 [ # # ]: 0 : if (!p->mss_mod) {
561 [ # # ]: 0 : if (mss ^ p->mss) { p = p->next; continue; }
562 [ # # ]: 0 : } else if (mss % p->mss) { p = p->next; continue; }
563 : :
564 [ # # ]: 0 : if (!p->wsc_mod) {
565 [ # # ]: 0 : if (wsc ^ p->wsc) { p = p->next; continue; }
566 [ # # ]: 0 : } else if (wsc % p->wsc) { p = p->next; continue; }
567 : :
568 : : /* Then proceed with the most complex WSS check... */
569 [ # # # # : 0 : switch (p->wsize_mod)
# ]
570 : : {
571 : : case 0:
572 [ # # ]: 0 : if (wss ^ p->wsize) { p = p->next; continue; }
573 : 0 : break;
574 : : case MOD_CONST:
575 [ # # ]: 0 : if (wss % p->wsize) { p = p->next; continue; }
576 : 0 : break;
577 : : case MOD_MSS:
578 [ # # ][ # # ]: 0 : if (mss && !(wss % mss))
579 : : {
580 [ # # ]: 0 : if ((wss / mss) ^ p->wsize) { p = p->next; continue; }
581 : : }
582 [ # # ]: 0 : else if (!(wss % 1460))
583 : : {
584 [ # # ]: 0 : if ((wss / 1460) ^ p->wsize) { p = p->next; continue; }
585 : : }
586 : 0 : else { p = p->next; continue; }
587 : 0 : break;
588 : : case MOD_MTU:
589 [ # # ][ # # ]: 0 : if (mss && !(wss % (mss+40)))
590 : : {
591 [ # # ]: 0 : if ((wss / (mss+40)) ^ p->wsize) { p = p->next; continue; }
592 : : }
593 [ # # ]: 0 : else if (!(wss % 1500))
594 : : {
595 [ # # ]: 0 : if ((wss / 1500) ^ p->wsize) { p = p->next; continue; }
596 : : }
597 : 0 : else { p = p->next; continue; }
598 : : break;
599 : : }
600 : :
601 : : /* Numbers agree. Let's check options */
602 [ # # ]: 0 : for (j=0;j<ocnt;j++)
603 [ # # ]: 0 : if (p->opt[j] ^ op[j]) goto continue_search;
604 : :
605 : : /* Check TTLs last because we might want to go fuzzy. */
606 [ # # ]: 0 : if (p->ttl < ttl)
607 : : {
608 [ # # ]: 0 : if ( mode != RST_FINGERPRINT_MODE )fuzzy = p;
609 : 0 : p = p->next;
610 : 0 : continue;
611 : : }
612 : :
613 : : /* Naah... can't happen ;-) */
614 [ # # ]: 0 : if (!p->no_detail)
615 [ # # ]: 0 : if (p->ttl - ttl > MAXDIST)
616 : : {
617 [ # # ]: 0 : if (mode != RST_FINGERPRINT_MODE ) fuzzy = p;
618 : 0 : p = p->next;
619 : 0 : continue;
620 : : }
621 : :
622 : 0 : continue_fuzzy:
623 : :
624 : : /* Match! */
625 : 0 : id = p->line;
626 [ # # ]: 0 : if (mss & wss)
627 : : {
628 [ # # ]: 0 : if (p->wsize_mod == MOD_MSS)
629 : : {
630 [ # # ][ # # ]: 0 : if ((wss % mss) && !(wss % 1460)) retval->gadgets|=GADGETNAT;
631 : : }
632 [ # # ]: 0 : else if (p->wsize_mod == MOD_MTU)
633 : : {
634 [ # # ][ # # ]: 0 : if ((wss % (mss+40)) && !(wss % 1500)) retval->gadgets|=GADGETNAT2;
635 : : }
636 : : }
637 : :
638 : 0 : retval->os=p->os;
639 : 0 : retval->desc=p->desc;
640 : 0 : retval->dist=p->ttl-ttl;
641 : :
642 [ # # ]: 0 : if (ecn) retval->gadgets|=GADGETECN;
643 [ # # ]: 0 : if (orig_df ^ df) retval->gadgets|=GADGETFIREWALL;
644 : :
645 [ # # ]: 0 : if (p->generic) retval->match=MATCHGENERIC;
646 [ # # ]: 0 : if (fuzzy_now) retval->match=MATCHFUZZY;
647 : :
648 [ # # ][ # # ]: 0 : if (!p->no_detail && tstamp)
649 : : {
650 : 0 : retval->uptime=tstamp/360000;
651 : 0 : retval->gadgets|=GADGETUPTIME;
652 : : }
653 : :
654 : 0 : return id;
655 : :
656 : 0 : continue_search:
657 : :
658 : 0 : p = p->next;
659 : :
660 : : }
661 : :
662 [ # # ]: 0 : if (!df) { df = 1; goto re_lookup; } //not found with df=0 do df=1
663 : :
664 [ # # ]: 0 : if (fuzzy)
665 : : {
666 : 0 : df = orig_df;
667 : 0 : fuzzy_now = 1;
668 : 0 : p = fuzzy;
669 : 0 : fuzzy = 0;
670 : 0 : goto continue_fuzzy;
671 : : }
672 : :
673 [ # # ]: 0 : if (mss & wss)
674 : : {
675 [ # # ][ # # ]: 0 : if ((wss % mss) && !(wss % 1460)) retval->gadgets|=GADGETNAT;
676 [ # # ][ # # ]: 0 : else if ((wss % (mss+40)) && !(wss % 1500)) retval->gadgets|=GADGETNAT2;
677 : : }
678 : :
679 [ # # ]: 0 : if (ecn) retval->gadgets|=GADGETECN;
680 : :
681 [ # # ]: 0 : if (tstamp)
682 : : {
683 : 0 : retval->uptime=tstamp/360000;
684 : 0 : retval->gadgets|=GADGETUPTIME;
685 : : }
686 : :
687 : 0 : return id;
688 [ + - ][ + - ]: 6 : }
|