Merge pull request #56 from wuruilong01/master
[prads.git] / src / sig_tcp.c
blob2b298d619ba5edb19e8cfcde185ed9d4e2b4db56
1 /* Load and match signatures
3 * (c) Kacper Wysocki <kacperw@gmail.com> for PRADS, 2009
5 * straight port of p0f load,match_sigs and support functions - nothing new here
7 * p0f loads sigs as struct fp_entry into the sig[] array
8 * ... and uses a static hash lookup to jump into this array
9 * - based on size, option count, quirks and don't fragment
11 * thoughts to improve:
12 - decouple fingerprints from signatures,
13 provide consistent interface for matching assets
14 across services (arp,ip,tcp,udp,link,dhcp,...)
16 *** The interface (should be) ***
18 *** sigs ***
19 load_sigs() <- create hashtable from file
20 usage:
21 sigs* = load_sigs(file)
22 load_sigs_{syn,ack,synack,..}()
24 match_fp(char *fp, struct *fp) <- take a fingerprint string/struct
25 and lookup into hash. return unique, fuzzy, best match.
27 match_fp(packetinfo) - guess OS based on packet info
29 TODO:
30 - ipv6 fix
31 - collide
32 - frob ipfp* stuff for sanity
33 - walk through find_match() and return the match properly
34 - run update_asset_os() with a looked-up asset
35 - sanity check asset lookups
37 update_asset_os(pi, de, fp, tstamp?tstamp:0);
39 - prepare_tcp()
40 - parse_tcp()
45 #include "common.h"
46 #include "prads.h"
47 #include "dhcp.h"
48 #include "sys_func.h"
49 #include "mtu.h"
50 #include "tos.h"
51 #include "config.h"
52 #include "assets.h"
54 extern globalconfig config;
56 #define MAXLINE 1024
57 #define SIG_HASHSIZE 1024
58 #define MAXDIST 512
59 #define PKT_DLEN 16
60 #define PKT_MAXPAY 145
62 // in open mode, how many options to parse
63 #define TCPOPT_LIMIT 3
65 /* SIGHASH needs some tweaking
66 * the addition of wsize has reduced collisions
67 * but similar signatures still collide.
69 * best case (and least efficient) would be to hash on
70 * full options and quirks
72 #define SIGHASH(tsize,optcnt,q,df) \
73 ( ((tsize) << 2) ^ ((optcnt) << 1) ^ (df) ^ (q) )
74 //( ((wsize) << 3) ^ ((tsize) << 2) ^ ((optcnt) << 1) ^ (df) ^ (q) )
76 uint32_t packet_count;
77 uint8_t operating_mode;
78 uint32_t st_time;
79 static uint8_t no_extra,
80 no_osdesc,
81 no_known,
82 no_unknown,
83 rst_mode,
84 mode_oneline,
85 always_sig,
86 do_resolve,
87 check_collide,
88 full_dump, use_fuzzy, payload_dump;
91 bstring gen_fp_tcpopt(uint32_t ocnt, uint8_t op[], uint16_t mss, uint16_t wss, uint16_t wsc, uint32_t tstamp)
93 uint32_t j;
94 bstring fp = bformat("");
95 for (j = 0; j < ocnt; j++) {
96 switch (op[j]) {
97 case TCPOPT_NOP:
98 bformata(fp, "N");
99 break;
100 case TCPOPT_WSCALE:
101 bformata(fp, "W%d", wsc);
102 break;
103 case TCPOPT_MAXSEG:
104 bformata(fp, "M%d", mss);
105 break;
106 case TCPOPT_TIMESTAMP:
107 bformata(fp, "T");
108 if (!tstamp)
109 bformata(fp, "0");
110 break;
111 case TCPOPT_SACKOK:
112 bformata(fp, "S");
113 break;
114 case TCPOPT_EOL:
115 bformata(fp, "E");
116 break;
117 default:
118 bformata(fp, "?%d", op[j]);
119 break;
121 if(!config.tcpopt_parsable) // experimental format change!
122 if (j != ocnt - 1)
123 bformata(fp, ",");
126 if (blength(fp) < 2)
127 bformata(fp, ".");
129 return fp;
132 bstring gen_fp_tcpquirks(uint32_t quirks)
134 bstring fp = bformat("");
135 if (!quirks)
136 bformata(fp, ".");
137 else {
138 if (quirks & QUIRK_RSTACK)
139 bformata(fp, "K");
140 if (quirks & QUIRK_SEQEQ)
141 bformata(fp, "Q");
142 if (quirks & QUIRK_SEQ0)
143 bformata(fp, "0");
144 if (quirks & QUIRK_PAST)
145 bformata(fp, "P");
146 if (quirks & QUIRK_ZEROID)
147 bformata(fp, "Z");
148 if (quirks & QUIRK_IPOPT)
149 bformata(fp, "I");
150 if (quirks & QUIRK_URG)
151 bformata(fp, "U");
152 if (quirks & QUIRK_X2)
153 bformata(fp, "X");
154 if (quirks & QUIRK_ACK)
155 bformata(fp, "A");
156 if (quirks & QUIRK_T2)
157 bformata(fp, "T");
158 if (quirks & QUIRK_FLAGS)
159 bformata(fp, "F");
160 if (quirks & QUIRK_DATA)
161 bformata(fp, "D");
163 // edward
164 if (quirks & QUIRK_FINACK)
165 bformata(fp, "N");
166 if (quirks & QUIRK_FLOWL)
167 bformata(fp, "L");
169 if (quirks & QUIRK_BROKEN)
170 bformata(fp, "!");
172 return fp;
176 /* generate a bstring fingerprint based on packet
177 * allocates memory */
178 bstring gen_fp_tcp(fp_entry *e, uint32_t tstamp, uint8_t tf)
180 uint8_t ttl,
181 uint16_t tot,
182 uint8_t df,
183 uint8_t * op,
184 uint8_t ocnt,
185 uint16_t mss,
186 uint16_t wss,
187 uint8_t wsc,
188 uint32_t tstamp,
189 uint32_t quirks,
190 uint8_t ftype,
191 packetinfo *pi)
195 uint16_t mss, wss, tot;
196 uint8_t ttl;
197 bstring fp, fpopt, fpquirks;
198 //uint8_t q = 0;
200 mss = e->mss;
201 wss = e->wsize;
202 tot = e->size;
203 ttl = e->ttl; //normalize_ttl(e->ttl);
204 fp = bformat("");
206 // mss/wss code might make the fpstring look different from the file sig
207 if (mss && wss && !(wss % mss))
208 bformata(fp, "S%d", (wss / mss));
209 else if (wss && !(wss % 1460))
210 bformata(fp, "S%d", (wss / 1460));
211 else if (mss && wss && !(wss % (mss + 40)))
212 bformata(fp, "T%d", (wss / (mss + 40)));
213 else if (wss && !(wss % 1500))
214 bformata(fp, "T%d", (wss / 1500));
215 else if (wss == 12345)
216 bformata(fp, "*(12345)");
217 else {
218 bformata(fp, "%d", wss);
221 if ( tf == TF_ACK || tf == TF_RST ) {
222 bformata(fp, ":%d:%d:*:",ttl, e->df);
223 } else {
224 if (e->size < PACKET_BIG)
225 bformata(fp, ":%d:%d:%d:", ttl, e->df, e->size);
226 else
227 bformata(fp, ":%d:%d:*(%d):", ttl, e->df, e->size);
230 // TCP Options
231 fpopt = gen_fp_tcpopt(( tf == TF_ACK? TCPOPT_LIMIT : e->optcnt), e->opt, mss, wss, e->wsc, tstamp);
232 bconcat(fp, fpopt);
233 bdestroy(fpopt);
235 bformata(fp, ":");
237 // Quirks
238 fpquirks = gen_fp_tcpquirks(e->quirks);
239 bconcat(fp, fpquirks);
240 bdestroy(fpquirks);
242 //if (tstamp) printf("(* uptime: %d hrs)\n",tstamp/360000);
243 //update_asset_os(pi, tf, fp, tstamp?tstamp:0);
244 return fp;
247 void print_sig(fp_entry * e)
249 // gen_fp_tcp takes (fingerprint, uptime, TCP_FLAG)
250 // meaning that e->zero_stamp is wrong!
251 bstring b = gen_fp_tcp(e, e->zero_stamp, 0);
252 char *c = bstr2cstr(b, '-');
253 printf("[%s", c);
254 bcstrfree(c);
255 bdestroy(b);
257 printf("],%s:%s\n", e->os, e->desc);
259 void print_sigs(fp_entry * e)
261 print_sig(e);
262 if (e->next)
263 print_sigs(e->next);
266 /* collide: check
267 static void collide(uint32_t id)
269 uint32_t i, j;
270 uint32_t cur;
272 if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30) {
273 problems = 1;
274 debug("[!] Unusual TTL (%d) for signature '%s %s' (line %d).\n",
275 sig[id].ttl, sig[id].os, sig[id].desc, sig[id].line);
278 for (i = 0; i < id; i++) {
280 if (!strcmp(sig[i].os, sig[id].os) &&
281 !strcmp(sig[i].desc, sig[id].desc)) {
282 problems = 1;
283 debug
284 ("[!] Duplicate signature name: '%s %s' (line %d and %d).\n",
285 sig[i].os, sig[i].desc, sig[i].line, sig[id].line);
288 //If TTLs are sufficiently away from each other, the risk of
289 // a collision is lower.
290 if (abs((int32_t) sig[id].ttl - (int32_t) sig[i].ttl) > 25)
291 continue;
293 if (sig[id].df ^ sig[i].df)
294 continue;
295 if (sig[id].zero_stamp ^ sig[i].zero_stamp)
296 continue;
298 // * Zero means >= PACKET_BIG
299 if (sig[id].size) {
300 if (sig[id].size ^ sig[i].size)
301 continue;
302 } else if (sig[i].size < PACKET_BIG)
303 continue;
305 if (sig[id].optcnt ^ sig[i].optcnt)
306 continue;
307 if (sig[id].quirks ^ sig[i].quirks)
308 continue;
310 switch (sig[id].wsize_mod) {
312 case 0: // Current: const
314 cur = sig[id].wsize;
316 do_const:
318 switch (sig[i].wsize_mod) {
320 case 0: // Previous is also const
322 // * A problem if values match
323 if (cur ^ sig[i].wsize)
324 continue;
325 break;
327 case MOD_CONST: // Current: const, prev: modulo (or *)
329 // A problem if current value is a multiple of that modulo
330 if (cur % sig[i].wsize)
331 continue;
332 break;
334 case MOD_MSS: // Current: const, prev: mod MSS
336 if (sig[i].mss_mod || sig[i].wsize *
337 (sig[i].mss ? sig[i].mss : 1460) != cur)
338 continue;
340 break;
342 case MOD_MTU: // Current: const, prev: mod MTU
344 if (sig[i].mss_mod
345 || sig[i].wsize * ((sig[i].mss ? sig[i].mss : 1460) +
346 40) != cur)
347 continue;
349 break;
353 break;
355 case 1: // Current signature is modulo something
357 // A problem only if this modulo is a multiple of the
358 // previous modulo
360 if (sig[i].wsize_mod != MOD_CONST)
361 continue;
362 if (sig[id].wsize % sig[i].wsize)
363 continue;
365 break;
367 case MOD_MSS: // Current is modulo MSS
369 // There's likely a problem only if the previous one is close
370 // to '*'; we do not check known MTUs, because this particular
371 // signature can be made with some uncommon MTUs in mind. The
372 // problem would also appear if current signature has a fixed
373 // MSS.
375 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
376 if (!sig[id].mss_mod) {
377 cur =
378 (sig[id].mss ? sig[id].mss : 1460) * sig[id].wsize;
379 goto do_const;
381 continue;
384 break;
386 case MOD_MTU: // Current is modulo MTU
388 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize <= 8) {
389 if (!sig[id].mss_mod) {
390 cur =
391 ((sig[id].mss ? sig[id].mss : 1460) +
392 40) * sig[id].wsize;
393 goto do_const;
395 continue;
398 break;
402 // Same for wsc
403 switch (sig[id].wsc_mod) {
405 case 0: // Current: const
407 cur = sig[id].wsc;
409 switch (sig[i].wsc_mod) {
411 case 0: // Previous is also const
413 // A problem if values match
414 if (cur ^ sig[i].wsc)
415 continue;
416 break;
418 case 1: // Current: const, prev: modulo (or *)
420 // A problem if current value is a multiple of that modulo
421 if (cur % sig[i].wsc)
422 continue;
423 break;
427 break;
429 case MOD_CONST: // Current signature is modulo something
431 // A problem only if this modulo is a multiple of the
432 // previous modulo
434 if (!sig[i].wsc_mod)
435 continue;
436 if (sig[id].wsc % sig[i].wsc)
437 continue;
439 break;
443 // Same for mss
444 switch (sig[id].mss_mod) {
446 case 0: // Current: const
448 cur = sig[id].mss;
450 switch (sig[i].mss_mod) {
452 case 0: // Previous is also const
454 // A problem if values match
455 if (cur ^ sig[i].mss)
456 continue;
457 break;
459 case 1: // Current: const, prev: modulo (or *)
461 // A problem if current value is a multiple of that modulo
462 if (cur % sig[i].mss)
463 continue;
464 break;
468 break;
470 case MOD_CONST: // Current signature is modulo something
472 // A problem only if this modulo is a multiple of the
473 // previous modulo
474 if (!sig[i].mss_mod)
475 continue;
476 if ((sig[id].mss ? sig[id].mss : 1460) %
477 (sig[i].mss ? sig[i].mss : 1460))
478 continue;
480 break;
484 // Now check option sequence
485 for (j = 0; j < sig[id].optcnt; j++)
486 if (sig[id].opt[j] ^ sig[i].opt[j])
487 goto reloop;
489 problems = 1;
490 debug("[!] Signature '%s %s' (line %d)\n"
491 " is already covered by '%s %s' (line %d).\n",
492 sig[id].os, sig[id].desc, sig[id].line, sig[i].os,
493 sig[i].desc, sig[i].line);
495 reloop:
499 //collide () */
500 /* recursively free signatures */
501 static void free_sigs(fp_entry *e){
502 if(e->next)
503 free_sigs(e->next);
504 free(e->os);
505 free(e->desc);
506 free(e);
509 /* alloc_sig return a newly allocated copy of *e */
510 static fp_entry *alloc_sig(fp_entry *e)
512 fp_entry *n = calloc(1, sizeof(fp_entry));
513 *n = *e; // copy
514 return n;
517 /* parse the wss field of the signature line */
518 static int parse_sig_wsize(fp_entry *sig, char* w)
520 if (w[0] == '*') {
521 sig->wsize = 1;
522 sig->wsize_mod = MOD_CONST;
523 } else if (tolower(w[0]) == 's') {
524 sig->wsize_mod = MOD_MSS;
525 if (!isdigit(*(w + 1)))
526 fatal("Bad Snn value in WSS in line %d.\n", sig->line);
527 sig->wsize = atoi(w + 1);
528 } else if (tolower(w[0]) == 't') {
529 sig->wsize_mod = MOD_MTU;
530 if (!isdigit(*(w + 1)))
531 fatal("Bad Tnn value in WSS in line %d.\n", sig->line);
532 sig->wsize = atoi(w + 1);
533 } else if (w[0] == '%') {
534 if (!(sig->wsize = atoi(w + 1)))
535 fatal("Null modulo for window size in config line %d.\n",
536 sig->line);
537 sig->wsize_mod = MOD_CONST;
538 } else
539 sig->wsize = atoi(w);
541 return 0;
544 /* parse the option field of the signature line */
545 static int parse_sig_options(fp_entry *sig, char* p)
547 sig->zero_stamp = 1;
549 if (*p == '.')
550 p++;
552 while (*p) {
553 uint8_t optcnt = sig->optcnt;
554 switch (tolower(*p)) {
556 case 'n':
557 sig->opt[optcnt] = TCPOPT_NOP;
558 break;
560 case 'e':
561 sig->opt[optcnt] = TCPOPT_EOL;
562 //if (*(p + 1)) // Old! Improved fingerprints with also collecting options after EOL
563 // fatal("EOL not the last option (line %d).\n", sig->line);
564 break;
566 case 's':
567 sig->opt[optcnt] = TCPOPT_SACKOK;
568 break;
570 case 't':
571 sig->opt[optcnt] = TCPOPT_TIMESTAMP;
572 if (*(p + 1) != '0') {
573 sig->zero_stamp = 0;
574 if (isdigit(*(p + 1)))
575 fatal("Bogus Tstamp specification in line %d.\n",
576 sig->line);
578 break;
580 case 'w':
581 sig->opt[optcnt] = TCPOPT_WSCALE;
582 if (p[1] == '*') {
583 sig->wsc = 1;
584 sig->wsc_mod = MOD_CONST;
585 } else if (p[1] == '%') {
586 if (!(sig->wsc = atoi(p + 2)))
587 fatal
588 ("Null modulo for wscale in config line %d.\n",
589 sig->line);
590 sig->wsc_mod = MOD_CONST;
591 } else if (!isdigit(*(p + 1)))
592 fatal("Incorrect W value in line %d.\n", sig->line);
593 else
594 sig->wsc = atoi(p + 1);
595 break;
597 case 'm':
598 sig->opt[optcnt] = TCPOPT_MAXSEG;
599 if (p[1] == '*') {
600 sig->mss = 1;
601 sig->mss_mod = MOD_CONST;
602 } else if (p[1] == '%') {
603 if (!(sig->mss = atoi(p + 2)))
604 fatal("Null modulo for MSS in config line %d.\n",
605 sig->line);
606 sig->mss_mod = MOD_CONST;
607 } else if (!isdigit(*(p + 1)))
608 fatal("Incorrect M value in line %d.\n", sig->line);
609 else
610 sig->mss = atoi(p + 1);
611 break;
614 * Yuck!
616 case '?':
617 if (!isdigit(*(p + 1)))
618 fatal("Bogus ?nn value in line %d.\n", sig->line);
619 else
620 sig->opt[optcnt] = atoi(p + 1);
621 break;
623 default:
624 fatal("Unknown TCP option '%c' in config line %d.\n", *p,
625 sig->line);
628 if (++sig->optcnt >= MAXOPT)
629 fatal
630 ("Too many TCP options specified in config line %d.\n",
631 sig->line);
634 * Skip separators
636 do {
637 p++;
638 } while (*p && !isalpha(*p) && *p != '?');
640 return 0;
643 /* parse the quirks field of the signature line */
644 static int parse_sig_quirks(fp_entry *sig, uint8_t *p)
646 while (*p){
647 switch (toupper(*(p++))) {
648 case 'E':
649 fatal
650 ("Quirk 'E' (line %d) is obsolete. Remove it, append E to the "
651 "options.\n", sig->line);
653 case 'K':
654 //if (!rst_mode)
655 if (!IS_COSET(&config,CO_RST))
656 fatal("Quirk 'K' (line %d) is valid only in RST+ (-R)"
657 " mode (wrong config file?).\n", sig->line);
658 sig->quirks |= QUIRK_RSTACK;
659 break;
661 case 'D':
662 sig->quirks |= QUIRK_DATA;
663 break;
665 case 'Q':
666 sig->quirks |= QUIRK_SEQEQ;
667 break;
668 case '0':
669 sig->quirks |= QUIRK_SEQ0;
670 break;
671 case 'P':
672 sig->quirks |= QUIRK_PAST;
673 break;
674 case 'Z':
675 sig->quirks |= QUIRK_ZEROID;
676 break;
677 case 'I':
678 sig->quirks |= QUIRK_IPOPT;
679 break;
680 case 'U':
681 sig->quirks |= QUIRK_URG;
682 break;
683 case 'X':
684 sig->quirks |= QUIRK_X2;
685 break;
686 case 'A':
687 sig->quirks |= QUIRK_ACK;
688 break;
689 case 'T':
690 sig->quirks |= QUIRK_T2;
691 break;
692 case 'F':
693 sig->quirks |= QUIRK_FLAGS;
694 break;
695 case 'N':
696 sig->quirks |= QUIRK_FINACK;
697 break;
698 case 'L':
699 sig->quirks |= QUIRK_FLOWL;
700 break;
701 case '!':
702 sig->quirks |= QUIRK_BROKEN;
703 break;
704 case '.':
705 break;
706 default:
707 fatal("Bad quirk '%c' in line %d.\n", *(p - 1), sig->line);
710 return 0;
715 /* load_sigs: fill **sig with fp_entry signatures from *file
717 * sigp is a pointer to either
718 ** a pointer to a preallocated buffer of size max_sigs * fp_entry OR
719 ** a NULL pointer indicating that we should allocate max_sigs for you
720 * max_sigs is the maximal size of the buffer, or 0 in which case we decide
722 * Theory: snarf sigs in serially, easypeasy
723 * Practice: lookups are a bitch and require a buckethash.
724 ** -> store sigs directly into hash.
726 * returns errno
728 int load_sigs(const char *file, fp_entry **sigp[], int hashsize)
730 fp_entry **sig; // output
731 uint32_t ln = 0;
732 //debug("opening %s\n", file);
733 FILE *f = fopen(file, "r");
734 char buf[MAXLINE];
735 char *p;
736 if (!f) {
737 perror("failed to open file");
738 return errno;
740 if(!sigp){
741 fclose(f);
742 perror("need a pointer to fill");
743 return -1;
745 if(!hashsize)
746 hashsize = SIG_HASHSIZE;
747 if(*sigp == NULL){
748 *sigp = calloc(hashsize, sizeof(fp_entry*));
749 sig = *sigp;
752 while ((p = fgets(buf, sizeof(buf), f))) {
753 uint32_t l;
755 char obuf[MAXLINE], genre[MAXLINE], desc[MAXLINE];
756 uint8_t quirks[MAXLINE];
757 char w[MAXLINE], sb[MAXLINE];
758 char *gptr = genre;
759 uint32_t t, d, s;
760 fp_entry asig = {0}; //guarantee it's empty this sig
761 fp_entry *e;
763 ln++;
765 /* Remove leading and trailing blanks */
766 while (isspace(*p))
767 p++;
768 l = strlen(p);
769 while (l && isspace(*(p + l - 1)))
770 *(p + (l--) - 1) = 0;
772 /* Skip empty lines and comments */
773 if (!l)
774 continue;
775 if (*p == '#')
776 continue;
778 if (sscanf
779 (p, "%[0-9%*()ST]:%d:%d:%[0-9()*]:%[^:]:%[^ :]:%[^:]:%[^:]",
780 w, &t, &d, sb, obuf, quirks, genre, desc) != 8)
781 fatal("Syntax error in config line %d.\n", ln);
783 gptr = genre;
785 if (*sb != '*') {
786 s = atoi(sb);
787 } else
788 s = 0;
790 reparse_ptr:
792 switch (*gptr) {
793 case '-':
794 asig.userland = 1;
795 gptr++;
796 goto reparse_ptr;
797 case '*':
798 asig.no_detail = 1;
799 gptr++;
800 goto reparse_ptr;
801 case '@':
802 asig.generic = 1;
803 gptr++;
804 //gencnt++;
805 goto reparse_ptr;
806 case 0:
807 fatal("Empty OS genre in line %d.\n", ln);
810 asig.os = strdup(gptr);
811 asig.desc = strdup(desc);
812 asig.ttl = t;
813 asig.size = s;
814 asig.df = d;
816 parse_sig_wsize(&asig, w);
817 asig.line = ln;
818 parse_sig_options(&asig, obuf);
819 parse_sig_quirks(&asig, quirks);
820 uint32_t index = SIGHASH(s, asig.optcnt, asig.quirks, d) % hashsize;
821 e = sig[index];
823 if (!e) {
824 sig[index] = alloc_sig(&asig);
825 } else {
826 int cc = 0;
827 // collision!
828 while (e->next){
829 e = e->next;
830 cc++;
833 fprintf(stderr, "hash collision %d: \n%d: %s - %s\n%d: %s - %s\n",
834 cc, asig.line, asig.os, asig.desc, e->line, e->os, e->desc);
836 e->next = alloc_sig(&asig);
840 if (check_collide)
841 collide(sigcnt);
845 if (++sigcnt >= hashsize)
846 fatal("Maximum signature count exceeded.\n");
851 fclose(f);
852 #ifdef DUMP_SIG_HASH
854 int i;
855 for (i = 0; i < sigcnt; i++) {
856 print_sig(&sig[i]);
859 #endif
860 #ifdef DEBUG_HASH
862 int i;
863 fp_entry *p;
864 printf("Hash table layout: ");
865 for (i = 0; i < hashsize; i++) {
866 int z = 0;
867 p = sig[i];
868 while (p) {
869 p = p->next;
870 z++;
872 printf("%d ", z);
874 putchar('\n');
876 #endif /* DEBUG_HASH */
878 if (check_collide)
879 debug("[+] Signature collision check successful.\n");
882 if (!sigcnt)
883 debug("[!] WARNING: no signatures loaded from config file.\n");
886 return 0;
889 /* run through the hash, free entries, then free hash */
890 void unload_sigs(fp_entry **sigp, int size)
892 int i = size;
893 fp_entry *e;
894 while(i--){
895 e = sigp[i];
896 if (e)
897 free_sigs(e);
898 sigp[i] = NULL; // clear
900 free(*sigp);
901 *sigp = NULL;
906 /* a dns cache of one? */
907 #define MY_MAXDNS 32
909 #include <netdb.h>
910 static inline char* grab_name(uint8_t* a) {
911 struct hostent* r;
912 static char rbuf[MY_MAXDNS+6] = "/";
913 uint32_t j;
914 char *s,*d = rbuf+1;
916 if (!do_resolve) return "";
917 r = gethostbyaddr(a,4,AF_INET);
918 if (!r || !(s = r->h_name) || !(j = strlen(s))) return "";
919 if (j > MY_MAXDNS) return "";
921 while (j--) {
922 if (isalnum(*s) || *s == '-' || *s == '.') *d = *s;
923 else *d = '?';
924 d++; s++;
927 *d=0;
929 return rbuf;
935 uint8_t* lookup_link(uint16_t mss, uint8_t txt) {
936 uint32_t i;
937 static char tmp[32];
939 if (!mss) return txt ? "unspecified" : 0;
940 mss += 40;
942 for (i=0;i<MTU_CNT;i++) {
943 if (mss == mtu[i].mtu) return mtu[i].dev;
944 if (mss < mtu[i].mtu) goto unknown;
947 unknown:
949 if (!txt) return 0;
950 sprintf(tmp,"unknown-%d",mss);
951 return tmp;
956 static char* lookup_tos(uint8_t t) {
957 uint32_t i;
959 if (!t) return 0;
961 for (i=0;i<TOS_CNT;i++) {
962 if (t == tos[i].tos) return tos[i].desc;
963 if (t < tos[i].tos) break;
966 return 0;
971 void dump_packet(const uint8_t* pkt,uint16_t plen) {
972 uint32_t i;
973 uint8_t tbuf[PKT_DLEN+1];
974 uint8_t* t = tbuf;
976 for (i=0;i<plen;i++) {
977 uint8_t c = *(pkt++);
978 if (!(i % PKT_DLEN)) dlog(" [%02x] ",i);
979 dlog("%02x ",c);
980 *(t++) = isprint(c) ? c : '.';
981 if (!((i+1) % PKT_DLEN)) {
982 *t=0;
983 dlog(" | %s\n",(t=tbuf));
987 if (plen % PKT_DLEN) {
988 *t=0;
989 while (plen++ % PKT_DLEN) dlog(" ");
990 dlog(" | %s\n",tbuf);
996 void dump_payload(const uint8_t* data,uint16_t dlen) {
997 uint8_t tbuf[PKT_MAXPAY+2];
998 uint8_t* t = tbuf;
999 uint8_t i;
1000 uint8_t max = dlen > PKT_MAXPAY ? PKT_MAXPAY : dlen;
1002 if (!dlen) return;
1004 for (i=0;i<max;i++) {
1005 if (isprint(*data)) *(t++) = *data;
1006 else if (!*data) *(t++) = '?';
1007 else *(t++) = '.';
1008 data++;
1011 *t = 0;
1013 plog( " # Payload: \"%s\"%s",tbuf,dlen > PKT_MAXPAY ? "...\n" : "\n");
1018 /* parse TCP packet quirks */
1019 static inline void parse_quirks(uint8_t ftype, tcp_header *tcph, uint32_t *quirks)
1021 if (ftype == TF_RST && (tcph->t_flags & TF_ACK))
1022 *quirks |= QUIRK_RSTACK;
1023 if (ftype == TF_FIN && (tcph->t_flags & TF_ACK))
1024 *quirks |= QUIRK_FINACK;
1026 if (tcph->t_seq == tcph->t_ack)
1027 *quirks |= QUIRK_SEQEQ;
1028 if (!tcph->t_seq)
1029 *quirks |= QUIRK_SEQ0;
1030 // ftype makes little sense here
1031 if (tcph->t_flags & ~(TF_SYN | TF_ACK | TF_RST | TF_ECE | TF_CWR
1032 | ((ftype == TF_ACK)? TF_PUSH : 0)))
1033 *quirks |= QUIRK_FLAGS;
1034 if (tcph->t_ack)
1035 *quirks |= QUIRK_ACK;
1036 if (tcph->t_urgp)
1037 *quirks |= QUIRK_URG;
1038 if (TCP_X2(tcph))
1039 *quirks |= QUIRK_X2;
1041 /* parse TCP option header field
1042 * yes, this function returns the timestamp for now */
1043 static inline uint32_t parse_tcpopt(const uint8_t *opt_ptr, int32_t ilen, const uint8_t *end_ptr, fp_entry *e)
1045 uint8_t ocnt = 0;
1046 int32_t olen;
1047 // mnemonics
1048 uint32_t *quirks = &e->quirks;
1049 uint8_t *op = e->opt;
1050 // timestamp is 64bit, but see if I care
1051 uint32_t tstamp = 0;
1053 while (ilen > 0) {
1054 ilen--;
1056 // * let the phun begin...
1057 switch (*(opt_ptr++)) {
1058 case TCPOPT_EOL:
1059 // * EOL
1060 op[ocnt] = TCPOPT_EOL;
1062 if (ilen) {
1063 *quirks |= QUIRK_PAST;
1065 break;
1067 case TCPOPT_NOP:
1068 // * NOP
1069 op[ocnt] = TCPOPT_NOP;
1070 break;
1072 case TCPOPT_SACKOK:
1073 // * SACKOK LEN
1074 op[ocnt] = TCPOPT_SACKOK;
1075 ilen--;
1076 opt_ptr++;
1077 break;
1079 case TCPOPT_MAXSEG:
1080 // * MSS LEN D0 D1
1081 if (opt_ptr + 3 > end_ptr) {
1082 borken:
1083 *quirks |= QUIRK_BROKEN;
1084 goto end_parsing;
1086 op[ocnt] = TCPOPT_MAXSEG;
1087 e->mss = GET16(opt_ptr + 1);
1088 ilen -= 3;
1089 opt_ptr += 3;
1090 break;
1092 case TCPOPT_WSCALE:
1093 // * WSCALE LEN D0
1094 if (opt_ptr + 2 > end_ptr)
1095 goto borken;
1096 op[ocnt] = TCPOPT_WSCALE;
1097 e->wsc = *(uint8_t *) (opt_ptr + 1);
1098 ilen -= 2;
1099 opt_ptr += 2;
1100 break;
1102 case TCPOPT_TIMESTAMP:
1103 // * TSTAMP LEN T0 T1 T2 T3 A0 A1 A2 A3
1104 // ugly handling of a beautiful 64bit field
1105 if (opt_ptr + 9 > end_ptr)
1106 goto borken;
1107 op[ocnt] = TCPOPT_TIMESTAMP;
1109 memcpy(&tstamp, opt_ptr + 5, 4);
1110 if (tstamp)
1111 *quirks |= QUIRK_T2;
1113 memcpy(&tstamp, opt_ptr + 1, 4);
1114 tstamp = ntohl(tstamp);
1116 ilen -= 9;
1117 opt_ptr += 9;
1118 break;
1119 case TCPOPT_PROXBLUECOAT:
1120 case TCPOPT_PROXCISCO:
1121 case TCPOPT_PROXRIVERBED1:
1122 case TCPOPT_PROXRIVERBED2:
1123 dlog("magic middleware option %02x detected", *(opt_ptr - 1) );
1124 // fallthru for now..
1125 default:
1126 // * Hrmpf...
1127 if (opt_ptr + 1 > end_ptr)
1128 goto borken;
1130 op[ocnt] = *(opt_ptr - 1);
1131 olen = *(uint8_t *) (opt_ptr) - 1;
1132 if (olen > 32 || (olen < 0))
1133 goto borken;
1135 ilen -= olen;
1136 opt_ptr += olen;
1137 break;
1140 ocnt++;
1141 if (ocnt >= MAXOPT - 1)
1142 goto borken;
1144 // * Whoops, we're past end_ptr
1145 if (ilen > 0)
1146 if (opt_ptr >= end_ptr)
1147 goto borken;
1150 end_parsing:
1151 e->optcnt = ocnt;
1152 return tstamp;
1156 /* find_match(): lookup packet with fingerprint e and info pi in sighash sig[]
1158 * match is returned as e->os and e->desc in e
1159 * NB NOTE XXX: the os and desc fields are statically allocated, do not free()!
1161 fp_entry *find_match(
1162 fp_entry *sig[], uint32_t hashsize,
1163 fp_entry *e, packetinfo *pi,
1164 uint32_t tstamp,
1165 uint8_t plen,
1166 uint8_t *pay
1167 /* uses the following values
1168 // uint16_t tot // e->size
1169 // uint8_t df, // e->
1170 // uint8_t ttl,
1171 // uint16_t wss, // wsize
1172 // uint32_t src, // pi->ip_src
1173 // uint32_t dst, // pi
1174 // uint16_t sp, // ntohs(pi->tcph->src_port)
1175 // uint16_t dp,
1176 // uint8_t ocnt, // optcnt
1177 // uint8_t* op, // opt
1178 // uint16_t mss,
1179 // uint8_t wsc,
1180 // uint32_t tstamp, ****
1181 // uint8_t tos, // pi->ip4->ip_tos
1182 // uint32_t quirks, // e
1183 // uint8_t ecn, // pi->tcph->t_flags & (TF_ECE|TF|CWR) // oh really?
1184 // uint8_t* pkt, // pi->ip4
1189 uint32_t j;
1190 uint8_t nat=0;
1191 fp_entry* p;
1192 uint8_t orig_df = e->df;
1193 char* tos_desc = 0;
1195 fp_entry* fuzzy = 0;
1196 uint8_t fuzzy_now = 0;
1197 char outbuf[INET6_ADDRSTRLEN+1];
1199 uint8_t *payhead = 0x0;
1200 if(pi->ip4) {
1201 payhead = (uint8_t*) pi->ip4;
1202 }else if(pi->ip6) {
1203 payhead = (uint8_t*) pi->ip6;
1204 } // elsewise null
1206 //if ( sig == config.sig_ack ) e->optcnt = 3;
1208 re_lookup:
1210 p = sig[SIGHASH(e->size,e->optcnt,e->quirks,e->df) % hashsize];
1212 if (PI_IP4(pi)) tos_desc = lookup_tos(PI_TOS(pi));
1214 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1215 while (p) {
1217 /* Cheap and specific checks first... */
1218 // esize == 0 => open_mode
1219 if(e->size){
1220 /* psize set to zero means >= PACKET_BIG */
1221 if (p->size) { if (e->size ^ p->size) { p = p->next; continue; } }
1222 else if (e->size < PACKET_BIG) { p = p->next; continue; }
1225 if (e->optcnt ^ p->optcnt) { p = p->next; continue; }
1227 if (p->zero_stamp ^ (!tstamp)) { p = p->next; continue; }
1228 if (p->df ^ e->df) { p = p->next; continue; }
1229 if (p->quirks ^ e->quirks) { p = p->next; continue; }
1231 /* Check e->mss and WSCALE... */
1232 if (!p->mss_mod) {
1233 if (e->mss ^ p->mss) { p = p->next; continue; }
1234 } else if (e->mss % p->mss) { p = p->next; continue; }
1236 if (!p->wsc_mod) {
1237 if (e->wsc ^ p->wsc) { p = p->next; continue; }
1238 } else if (e->wsc % p->wsc) { p = p->next; continue; }
1240 /* Then proceed with the most complex e->wsize check... */
1241 switch (p->wsize_mod) {
1242 case 0:
1243 if (e->wsize ^ p->wsize) { p = p->next; continue; }
1244 break;
1245 case MOD_CONST:
1246 if (e->wsize % p->wsize) { p = p->next; continue; }
1247 break;
1248 case MOD_MSS:
1249 if (e->mss && !(e->wsize % e->mss)) {
1250 if ((e->wsize / e->mss) ^ p->wsize) { p = p->next; continue; }
1251 } else if (!(e->wsize % 1460)) {
1252 if ((e->wsize / 1460) ^ p->wsize) { p = p->next; continue; }
1253 } else { p = p->next; continue; }
1254 break;
1255 case MOD_MTU:
1256 if (e->mss && !(e->wsize % (e->mss+40))) {
1257 if ((e->wsize / (e->mss+40)) ^ p->wsize) { p = p->next; continue; }
1258 } else if (!(e->wsize % 1500)) {
1259 if ((e->wsize / 1500) ^ p->wsize) { p = p->next; continue; }
1260 } else { p = p->next; continue; }
1261 break;
1264 /* Numbers agree. Let's check options */
1266 for (j=0;j<e->optcnt;j++){
1267 if (p->opt[j] ^ e->opt[j]) goto continue_search;
1270 /* Check TTLs last because we might want to go fuzzy. */
1271 if (p->ttl < e->ttl) {
1272 if (use_fuzzy) fuzzy = p;
1273 p = p->next;
1274 continue;
1277 /* Naah... can't happen ;-) */
1278 if (!p->no_detail){
1279 if (p->ttl - e->ttl > MAXDIST) {
1280 if (use_fuzzy) fuzzy = p;
1281 p = p->next;
1282 continue;
1286 continue_fuzzy:
1288 /* Match! */
1290 if (e->mss & e->wsize) {
1291 if (p->wsize_mod == MOD_MSS) {
1292 if ((e->wsize % e->mss) && !(e->wsize % 1460)) nat=1;
1293 } else if (p->wsize_mod == MOD_MTU) {
1294 if ((e->wsize % (e->mss+40)) && !(e->wsize % 1500)) nat=2;
1298 if (!no_known) {
1300 // What about IPv6?
1302 // copy in the os/desc pointers. These are not to be free()d!
1303 e->os = p->os;
1304 e->desc = p->desc;
1307 /* TODO:many verbose checks could be made into os fields */
1308 if( config.verbose > 1 ){
1309 u_ntop_src(pi, outbuf);
1311 olog("%s:%d - %s ",outbuf, PI_TCP_SP(pi),p->os);
1313 if (!no_osdesc) olog("%s ",p->desc);
1314 if (nat == 1){
1315 olog("(NAT!) ");
1316 } else {
1317 if (nat == 2) olog("(NAT2!) ");
1320 if (PI_ECN(pi)) olog("(ECN) ");
1321 if (orig_df ^ e->df) olog("(firewall!) ");
1323 if (pi->ip4 && PI_TOS(pi)) {
1324 if (tos_desc) olog("[%s] ",tos_desc); else olog("[tos %d] ",PI_TOS(pi));
1326 if (p->no_detail) olog("* "); else
1327 if (tstamp) olog("(up: %d hrs) ",tstamp/360000);
1329 if (always_sig || (p->generic && !no_unknown)) {
1331 if (!mode_oneline) olog("\n ");
1332 olog("Signature: [");
1334 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1336 if (p->generic)
1337 olog(":%s:?] ",p->os);
1338 else
1339 olog("] ");
1342 if (!no_extra && !p->no_detail) {
1343 if (!mode_oneline) olog("\n ");
1345 u_ntop_dst(pi, outbuf);
1348 if (fuzzy_now)
1349 olog("-> %s:%d (link: %s)",outbuf, PI_TCP_DP(pi),
1350 lookup_link(e->mss,1));
1351 else
1352 olog("-> %s:%d (distance %d, link: %s)",outbuf, PI_TCP_DP(pi),
1353 p->ttl - e->ttl,
1354 lookup_link(e->mss,1));
1356 if (p->generic) olog("[GENERIC] ");
1357 if (fuzzy_now) olog("[FUZZY] ");
1358 olog("\n");
1361 if(payhead) {
1362 if (pay && payload_dump) dump_payload(pay,plen - (pay - payhead));
1364 if (full_dump) dump_packet(payhead,plen);
1369 /* find masquerade code... where is the sauce?
1370 if (find_masq && !p->userland) {
1371 int16_t sc = p0f_findmasq(src,p->os,(p->no_detail || fuzzy_now) ? -1 :
1372 (p->ttl - e->ttl), e->mss, nat, orig_df ^ e->df,p-sig,
1373 tstamp ? tstamp / 360000 : -1);
1374 a=(uint8_t*)& PI_IP4SRC(pi);
1375 if (sc > masq_thres) {
1376 printf(">> Masquerade at %u.%u.%u.%u%s: indicators at %d%%.",
1377 a[0],a[1],a[2],a[3],grab_name(a),sc);
1378 if (!mode_oneline) putchar('\n'); else printf(" -- ");
1379 if (masq_flags) {
1380 printf(" Flags: ");
1381 p0f_descmasq();
1382 putchar('\n');
1387 if (use_cache || find_masq)
1388 p0f_addcache(src,dst,sp,dp,p->os,p->desc,(p->no_detail || fuzzy_now) ?
1389 -1 : (p->ttl - e->ttl),p->no_detail ? 0 : lookup_link(e->mss,0),
1390 tos_desc, orig_df ^ e->df, nat, !p->userland, e->mss, p-sig,
1391 tstamp ? tstamp / 360000 : -1);
1394 fflush(0);
1396 return e;
1398 continue_search:
1400 p = p->next;
1404 if (!e->df) { e->df = 1; goto re_lookup; }
1406 if (use_fuzzy && fuzzy) {
1407 e->df = orig_df;
1408 fuzzy_now = 1;
1409 p = fuzzy;
1410 fuzzy = 0;
1411 goto continue_fuzzy;
1414 if (e->mss & e->wsize) {
1415 if ((e->wsize % e->mss) && !(e->wsize % 1460)) nat=1;
1416 else if ((e->wsize % (e->mss+40)) && !(e->wsize % 1500)) nat=2;
1419 if (!no_unknown) {
1420 if (config.verbose) {
1421 u_ntop_src(pi, outbuf);
1422 vlog(2,"%s:%d - UNKNOWN [:?:?]",outbuf,PI_TCP_SP(pi));
1425 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1427 if (rst_mode) {
1429 /* Display a reasonable diagnosis of the RST+ACK madness! */
1431 switch (e->quirks & (QUIRK_RSTACK | QUIRK_SEQ0 | QUIRK_ACK)) {
1433 /* RST+ACK, SEQ=0, ACK=0 */
1434 case QUIRK_RSTACK | QUIRK_SEQ0:
1435 vlog(2, "(invalid-K0) "); break;
1437 /* RST+ACK, SEQ=0, ACK=n */
1438 case QUIRK_RSTACK | QUIRK_ACK | QUIRK_SEQ0:
1439 vlog(2, "(refused) "); break;
1441 /* RST+ACK, SEQ=n, ACK=0 */
1442 case QUIRK_RSTACK:
1443 vlog(2, "(invalid-K) "); break;
1445 /* RST+ACK, SEQ=n, ACK=n */
1446 case QUIRK_RSTACK | QUIRK_ACK:
1447 vlog(2, "(invalid-KA) "); break;
1449 /* RST, SEQ=n, ACK=0 */
1450 case 0:
1451 vlog(2, "(dropped) "); break;
1453 /* RST, SEQ=m, ACK=n */
1454 case QUIRK_ACK:
1455 vlog(2, "(dropped 2) "); break;
1457 /* RST, SEQ=0, ACK=0 */
1458 case QUIRK_SEQ0:
1459 vlog(2, "(invalid-0) "); break;
1461 /* RST, SEQ=0, ACK=n */
1462 case QUIRK_ACK | QUIRK_SEQ0:
1463 vlog(2, "(invalid-0A) "); break;
1469 if (nat == 1) vlog(2, "(NAT!) ");
1470 else if (nat == 2) vlog(2, "(NAT2!) ");
1472 if (PI_ECN(pi)) vlog(2, "(ECN) ");
1474 if (pi->ip4 && PI_TOS(pi)) {
1475 if (tos_desc) vlog(2, "[%s] ",tos_desc); else vlog(2, "[tos %d] ",PI_TOS(pi));
1478 if (tstamp) vlog(2, "(up: %d hrs) ",tstamp/360000);
1480 if (!no_extra) {
1481 u_ntop_dst(pi, outbuf);
1482 //if (!mode_oneline) dlog("\n ");
1483 vlog(2, "-> %s:%d (link: %s)", outbuf,
1484 PI_TCP_DP(pi),lookup_link(e->mss,1));
1488 if (use_cache)
1489 p0f_addcache(src,dst,PI_TCP_SP(pi),PI_TCP_DP(pi),0,0,-1,lookup_link(e->mss,0),tos_desc,
1490 0,nat,0 // not real, we're not sure
1491 ,e->mss,(uint32_t)-1,
1492 tstamp ? tstamp / 360000 : -1);
1494 vlog(2, "\n");
1496 if(payhead) {
1497 if (pay && payload_dump) dump_payload(pay,plen - (pay - payhead));
1499 if (full_dump) dump_packet(payhead,plen);
1501 fflush(0);
1505 return e;
1509 // pass the pointers
1510 // unresolved: pass the packet?
1512 static inline void find_match_e(fp_entry *e, uint32_t tstamp, void *packet)
1514 return find_match(e->size, e->df, e->ttl, e->wsize, e->optcnt, e->opt, e->mss, e->wsc, tstamp, e->tos, e->quirks, e->ecn, packet, 0, 0, 0);
1519 /* my ideal interface
1520 fp_entry *lookup_sig(fp_entry sig[], packetinfo *pi)
1522 fp_entry *e = bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)];
1524 if (!e) {
1525 bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)] =
1526 sig + sigcnt;
1527 } else {
1528 while (e->next)
1529 e = e->next;
1530 e->next = sig + sigcnt;
1534 fp_entry *fp_tcp(packetinfo *pi, uint8_t ftype)
1536 uint8_t *opt_ptr;
1537 const uint8_t * end_ptr;
1538 uint8_t *payload = 0;
1539 fp_entry e = { 0 };
1540 int32_t ilen;
1541 uint32_t tstamp = 0;
1543 /* * If the declared length is shorter than the snapshot (etherleak
1544 * or such), truncate the package.
1545 * These tests are IP-specific and should one day go into into IP preproc*/
1546 end_ptr = pi->end_ptr;
1547 switch(pi->af){
1548 case AF_INET6:
1549 opt_ptr = (uint8_t *) pi->ip6 + IP6_HEADER_LEN + ntohs(pi->ip6->len); //*
1550 if (end_ptr > opt_ptr)
1551 end_ptr = opt_ptr;
1552 // If IP header ends past end_ptr
1553 if ((uint8_t *) (pi->ip6 + 1) > end_ptr)
1554 return NULL;
1555 if (IP6_FL(pi->ip6)) {
1556 /* http://tools.ietf.org/html/rfc2460#page-25
1557 The Flow Label field may be used by a source to label sequences of
1558 packets for which it requests special handling by the IPv6 routers.
1559 Mostly Zero today - subject to change in the future...
1560 Maybe parse_ipv6_fl() one day ?
1562 e.quirks |= QUIRK_FLOWL;
1564 e.ttl = pi->ip6->hop_lmt;
1565 e.size = (ftype == TF_ACK) ? 0 : ntohs(pi->ip6->len);
1566 e.df = 1; // for now
1567 if (!IP6_FL(pi->ip6)) //*
1568 e.quirks |= QUIRK_ZEROID;
1569 break;
1570 case AF_INET:
1571 opt_ptr = (uint8_t *) pi->ip4 + ntohs(pi->ip4->ip_len);
1572 if (end_ptr > opt_ptr)
1573 end_ptr = opt_ptr;
1574 if ((uint8_t *) (pi->ip4 + 1) > end_ptr)
1575 return NULL;
1576 ilen = pi->ip4->ip_vhl & 15;
1578 /* * B0rked packet */
1579 if (ilen < 5)
1580 return NULL;
1582 if (ilen > 5) {
1583 e.quirks |= QUIRK_IPOPT;
1585 e.ttl = pi->ip4->ip_ttl;
1586 e.size = (ftype == TF_ACK) ? 0 : ntohs(pi->ip4->ip_len);
1587 e.df = (ntohs(pi->ip4->ip_off) & IP_DF) != 0;
1588 if (!pi->ip4->ip_id)
1589 e.quirks |= QUIRK_ZEROID;
1590 break;
1591 // default: there is no default
1592 default:
1593 fprintf(stderr, "tcp_fp: something very unsafe happened!\n");
1594 return NULL;
1596 //printf("\nend_ptr:%u opt_ptr:%u",end_ptr,opt_ptr);
1598 parse_quirks(ftype,pi->tcph,&e.quirks);
1599 ilen = (TCP_OFFSET(pi->tcph) << 2) - TCP_HEADER_LEN;
1601 opt_ptr = (uint8_t *) (pi->tcph + 1);
1602 if ((uint8_t *) opt_ptr + ilen < end_ptr) {
1603 if (ftype != TF_ACK)
1604 e.quirks |= QUIRK_DATA;
1605 payload = opt_ptr + ilen;
1607 tstamp = parse_tcpopt(opt_ptr, ilen, pi->end_ptr, &e);
1608 //if (!tstamp) e.zero_stamp = 1;
1610 e.wsize = ntohs(pi->tcph->t_win);
1612 //if (pi->ip6 != NULL) return NULL; // Fix this when find_match() is IPv6 aware
1614 // match = find_match(sigs, pi, e);
1615 // ---> after match_network but before update_asset
1616 // find_match(pi, e);
1617 // return this into asset engine
1618 fp_entry **sig = NULL;
1619 if (ftype == CO_SYN) {
1620 sig=config.sig_syn;
1621 } else if (ftype == CO_SYNACK) {
1622 sig=config.sig_synack;
1623 } else if (ftype == CO_RST) {
1624 sig=config.sig_rst;
1625 } else if (ftype == CO_FIN) {
1626 sig=config.sig_fin;
1627 } else if (ftype == CO_ACK) {
1628 sig=config.sig_ack;
1632 fp_entry *match = NULL;
1633 if (sig != NULL) {
1634 match = find_match(sig,
1635 config.sig_hashsize,
1637 pi, // pass all packet characteristics
1638 tstamp,
1639 end_ptr - (uint8_t *) pi->ip4,
1640 payload
1644 //if (match->os != NULL) memcpy(&e.next->os, match->os, MAXLINE);
1645 //if (match->desc != NULL) memcpy(&e.next->desc, match->desc, MAXLINE);
1646 update_asset_os(pi, ftype, NULL, &e, tstamp);
1647 return NULL; // can't return stack-allocated * fp_entry e;
1649 printf("hop:%u, len:%u, ver:%u, class:%u, label:%u|mss:%u, win:%u\n",ip6->hop_lmt,open_mode ? 0 : ntohs(ip6->len),
1650 IP6_V(ip6),ntohs(IP6_TC(ip6)),
1651 ntohs(IP6_FL(ip6)),
1652 mss_val, ntohs(tcph->t_win));
1656 // /* sp */ ntohs(tcph->sport),
1657 // /* dp */ ntohs(tcph->dport),
1658 // /* ocnt */ ocnt,
1659 // /* op */ op,
1660 // /* mss */ mss_val,
1661 // /* wsc */ wsc_val,
1662 // /* tst */ tstamp,
1663 // /* TOS */ iph->tos,
1664 // /* Q? */ quirks,
1665 // /* ECN */ tcph->flags & (TH_ECE|TH_CWR),
1666 // /* pkt */ (_u8*)iph,
1667 // /* len */ end_ptr - (_u8*)iph,
1668 // /* pay */ pay,
1669 // /* ts */ pts
1670 // );
1676 void dump_sigs(fp_entry *mysig[], int max)
1678 int i;
1679 for (i = 0; i < max; i++){
1680 if (!mysig[i] || !mysig[i]->os)
1681 continue;
1682 print_sigs(mysig[i]);
1687 #ifdef SIG_STANDALONE
1688 #define HSIZE 241
1689 int main(int argc, char **argv)
1692 fp_entry **siga[16] = {0};
1693 int i = 0;
1694 if (argc < 2) {
1695 fprintf(stderr, "Where are my sigs?\n");
1696 exit(1);
1698 while (--argc) {
1699 argv++;
1700 load_sigs(*argv, &siga[i], HSIZE);
1701 dump_sigs(siga[i], HSIZE);
1702 unload_sigs(siga[i], HSIZE);
1707 #endif