indent dump_dns.c
[prads.git] / src / sig_tcp.c
blobc915542188b3854221ef64d3e7672500b6f469d9
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 "sys_func.h"
48 #include "mtu.h"
49 #include "tos.h"
50 #include "config.h"
51 #include "assets.h"
53 extern globalconfig config;
55 #define MAXLINE 1024
56 #define SIG_HASHSIZE 1024
57 #define MAXDIST 512
58 #define PKT_DLEN 16
59 #define PKT_MAXPAY 145
61 // in open mode, how many options to parse
62 #define TCPOPT_LIMIT 3
64 /* SIGHASH needs some tweaking
65 * the addition of wsize has reduced collisions
66 * but similar signatures still collide.
68 * best case (and least efficient) would be to hash on
69 * full options and quirks
71 #define SIGHASH(tsize,optcnt,q,df) \
72 ( ((tsize) << 2) ^ ((optcnt) << 1) ^ (df) ^ (q) )
73 //( ((wsize) << 3) ^ ((tsize) << 2) ^ ((optcnt) << 1) ^ (df) ^ (q) )
75 uint32_t packet_count;
76 uint8_t operating_mode;
77 uint32_t st_time;
78 static uint8_t no_extra,
79 no_osdesc,
80 no_known,
81 no_unknown,
82 rst_mode,
83 mode_oneline,
84 always_sig,
85 do_resolve,
86 check_collide,
87 full_dump, use_fuzzy, payload_dump;
90 bstring gen_fp_tcpopt(uint32_t ocnt, uint8_t op[], uint16_t mss, uint16_t wss, uint16_t wsc, uint32_t tstamp)
92 uint32_t j;
93 bstring fp = bformat("");
94 for (j = 0; j < ocnt; j++) {
95 switch (op[j]) {
96 case TCPOPT_NOP:
97 bformata(fp, "N");
98 break;
99 case TCPOPT_WSCALE:
100 bformata(fp, "W%d", wsc);
101 break;
102 case TCPOPT_MAXSEG:
103 bformata(fp, "M%d", mss);
104 break;
105 case TCPOPT_TIMESTAMP:
106 bformata(fp, "T");
107 if (!tstamp)
108 bformata(fp, "0");
109 break;
110 case TCPOPT_SACKOK:
111 bformata(fp, "S");
112 break;
113 case TCPOPT_EOL:
114 bformata(fp, "E");
115 break;
116 default:
117 bformata(fp, "?%d", op[j]);
118 break;
120 if (j != ocnt - 1)
121 bformata(fp, ",");
124 if (blength(fp) < 2)
125 bformata(fp, ".");
127 return fp;
130 bstring gen_fp_tcpquirks(uint32_t quirks)
132 bstring fp = bformat("");
133 if (!quirks)
134 bformata(fp, ".");
135 else {
136 if (quirks & QUIRK_RSTACK)
137 bformata(fp, "K");
138 if (quirks & QUIRK_SEQEQ)
139 bformata(fp, "Q");
140 if (quirks & QUIRK_SEQ0)
141 bformata(fp, "0");
142 if (quirks & QUIRK_PAST)
143 bformata(fp, "P");
144 if (quirks & QUIRK_ZEROID)
145 bformata(fp, "Z");
146 if (quirks & QUIRK_IPOPT)
147 bformata(fp, "I");
148 if (quirks & QUIRK_URG)
149 bformata(fp, "U");
150 if (quirks & QUIRK_X2)
151 bformata(fp, "X");
152 if (quirks & QUIRK_ACK)
153 bformata(fp, "A");
154 if (quirks & QUIRK_T2)
155 bformata(fp, "T");
156 if (quirks & QUIRK_FLAGS)
157 bformata(fp, "F");
158 if (quirks & QUIRK_DATA)
159 bformata(fp, "D");
161 // edward
162 if (quirks & QUIRK_FINACK)
163 bformata(fp, "N");
164 if (quirks & QUIRK_FLOWL)
165 bformata(fp, "L");
167 if (quirks & QUIRK_BROKEN)
168 bformata(fp, "!");
170 return fp;
174 /* generate a bstring fingerprint based on packet
175 * allocates memory */
176 bstring gen_fp_tcp(fp_entry *e, uint32_t tstamp, uint8_t tf)
178 uint8_t ttl,
179 uint16_t tot,
180 uint8_t df,
181 uint8_t * op,
182 uint8_t ocnt,
183 uint16_t mss,
184 uint16_t wss,
185 uint8_t wsc,
186 uint32_t tstamp,
187 uint32_t quirks,
188 uint8_t ftype,
189 packetinfo *pi)
193 uint16_t mss, wss, tot;
194 uint8_t ttl;
195 bstring fp, fpopt, fpquirks;
196 //uint8_t q = 0;
198 mss = e->mss;
199 wss = e->wsize;
200 tot = e->size;
201 ttl = e->ttl; //normalize_ttl(e->ttl);
202 fp = bformat("");
204 // mss/wss code might make the fpstring look different from the file sig
205 if (mss && wss && !(wss % mss))
206 bformata(fp, "S%d", (wss / mss));
207 else if (wss && !(wss % 1460))
208 bformata(fp, "S%d", (wss / 1460));
209 else if (mss && wss && !(wss % (mss + 40)))
210 bformata(fp, "T%d", (wss / (mss + 40)));
211 else if (wss && !(wss % 1500))
212 bformata(fp, "T%d", (wss / 1500));
213 else if (wss == 12345)
214 bformata(fp, "*(12345)");
215 else {
216 bformata(fp, "%d", wss);
219 if ( tf == TF_ACK || tf == TF_RST ) {
220 bformata(fp, ":%d:%d:*:",ttl, e->df);
221 } else {
222 if (e->size < PACKET_BIG)
223 bformata(fp, ":%d:%d:%d:", ttl, e->df, e->size);
224 else
225 bformata(fp, ":%d:%d:*(%d):", ttl, e->df, e->size);
228 // TCP Options
229 fpopt = gen_fp_tcpopt(( tf == TF_ACK? TCPOPT_LIMIT : e->optcnt), e->opt, mss, wss, e->wsc, tstamp);
230 bconcat(fp, fpopt);
231 bdestroy(fpopt);
233 bformata(fp, ":");
235 // Quirks
236 fpquirks = gen_fp_tcpquirks(e->quirks);
237 bconcat(fp, fpquirks);
238 bdestroy(fpquirks);
240 //if (tstamp) printf("(* uptime: %d hrs)\n",tstamp/360000);
241 //update_asset_os(pi, tf, fp, tstamp?tstamp:0);
242 return fp;
245 void print_sig(fp_entry * e)
247 // gen_fp_tcp takes (fingerprint, uptime, TCP_FLAG)
248 // meaning that e->zero_stamp is wrong!
249 bstring b = gen_fp_tcp(e, e->zero_stamp, 0);
250 char *c = bstr2cstr(b, '-');
251 printf("[%s", c);
252 bcstrfree(c);
254 printf("],%s:%s\n", e->os, e->desc);
256 void print_sigs(fp_entry * e)
258 print_sig(e);
259 if (e->next)
260 print_sigs(e->next);
263 /* collide: check
264 static void collide(uint32_t id)
266 uint32_t i, j;
267 uint32_t cur;
269 if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30) {
270 problems = 1;
271 debug("[!] Unusual TTL (%d) for signature '%s %s' (line %d).\n",
272 sig[id].ttl, sig[id].os, sig[id].desc, sig[id].line);
275 for (i = 0; i < id; i++) {
277 if (!strcmp(sig[i].os, sig[id].os) &&
278 !strcmp(sig[i].desc, sig[id].desc)) {
279 problems = 1;
280 debug
281 ("[!] Duplicate signature name: '%s %s' (line %d and %d).\n",
282 sig[i].os, sig[i].desc, sig[i].line, sig[id].line);
285 //If TTLs are sufficiently away from each other, the risk of
286 // a collision is lower.
287 if (abs((int32_t) sig[id].ttl - (int32_t) sig[i].ttl) > 25)
288 continue;
290 if (sig[id].df ^ sig[i].df)
291 continue;
292 if (sig[id].zero_stamp ^ sig[i].zero_stamp)
293 continue;
295 // * Zero means >= PACKET_BIG
296 if (sig[id].size) {
297 if (sig[id].size ^ sig[i].size)
298 continue;
299 } else if (sig[i].size < PACKET_BIG)
300 continue;
302 if (sig[id].optcnt ^ sig[i].optcnt)
303 continue;
304 if (sig[id].quirks ^ sig[i].quirks)
305 continue;
307 switch (sig[id].wsize_mod) {
309 case 0: // Current: const
311 cur = sig[id].wsize;
313 do_const:
315 switch (sig[i].wsize_mod) {
317 case 0: // Previous is also const
319 // * A problem if values match
320 if (cur ^ sig[i].wsize)
321 continue;
322 break;
324 case MOD_CONST: // Current: const, prev: modulo (or *)
326 // A problem if current value is a multiple of that modulo
327 if (cur % sig[i].wsize)
328 continue;
329 break;
331 case MOD_MSS: // Current: const, prev: mod MSS
333 if (sig[i].mss_mod || sig[i].wsize *
334 (sig[i].mss ? sig[i].mss : 1460) != cur)
335 continue;
337 break;
339 case MOD_MTU: // Current: const, prev: mod MTU
341 if (sig[i].mss_mod
342 || sig[i].wsize * ((sig[i].mss ? sig[i].mss : 1460) +
343 40) != cur)
344 continue;
346 break;
350 break;
352 case 1: // Current signature is modulo something
354 // A problem only if this modulo is a multiple of the
355 // previous modulo
357 if (sig[i].wsize_mod != MOD_CONST)
358 continue;
359 if (sig[id].wsize % sig[i].wsize)
360 continue;
362 break;
364 case MOD_MSS: // Current is modulo MSS
366 // There's likely a problem only if the previous one is close
367 // to '*'; we do not check known MTUs, because this particular
368 // signature can be made with some uncommon MTUs in mind. The
369 // problem would also appear if current signature has a fixed
370 // MSS.
372 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
373 if (!sig[id].mss_mod) {
374 cur =
375 (sig[id].mss ? sig[id].mss : 1460) * sig[id].wsize;
376 goto do_const;
378 continue;
381 break;
383 case MOD_MTU: // Current is modulo MTU
385 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize <= 8) {
386 if (!sig[id].mss_mod) {
387 cur =
388 ((sig[id].mss ? sig[id].mss : 1460) +
389 40) * sig[id].wsize;
390 goto do_const;
392 continue;
395 break;
399 // Same for wsc
400 switch (sig[id].wsc_mod) {
402 case 0: // Current: const
404 cur = sig[id].wsc;
406 switch (sig[i].wsc_mod) {
408 case 0: // Previous is also const
410 // A problem if values match
411 if (cur ^ sig[i].wsc)
412 continue;
413 break;
415 case 1: // Current: const, prev: modulo (or *)
417 // A problem if current value is a multiple of that modulo
418 if (cur % sig[i].wsc)
419 continue;
420 break;
424 break;
426 case MOD_CONST: // Current signature is modulo something
428 // A problem only if this modulo is a multiple of the
429 // previous modulo
431 if (!sig[i].wsc_mod)
432 continue;
433 if (sig[id].wsc % sig[i].wsc)
434 continue;
436 break;
440 // Same for mss
441 switch (sig[id].mss_mod) {
443 case 0: // Current: const
445 cur = sig[id].mss;
447 switch (sig[i].mss_mod) {
449 case 0: // Previous is also const
451 // A problem if values match
452 if (cur ^ sig[i].mss)
453 continue;
454 break;
456 case 1: // Current: const, prev: modulo (or *)
458 // A problem if current value is a multiple of that modulo
459 if (cur % sig[i].mss)
460 continue;
461 break;
465 break;
467 case MOD_CONST: // Current signature is modulo something
469 // A problem only if this modulo is a multiple of the
470 // previous modulo
471 if (!sig[i].mss_mod)
472 continue;
473 if ((sig[id].mss ? sig[id].mss : 1460) %
474 (sig[i].mss ? sig[i].mss : 1460))
475 continue;
477 break;
481 // Now check option sequence
482 for (j = 0; j < sig[id].optcnt; j++)
483 if (sig[id].opt[j] ^ sig[i].opt[j])
484 goto reloop;
486 problems = 1;
487 debug("[!] Signature '%s %s' (line %d)\n"
488 " is already covered by '%s %s' (line %d).\n",
489 sig[id].os, sig[id].desc, sig[id].line, sig[i].os,
490 sig[i].desc, sig[i].line);
492 reloop:
496 //collide () */
497 /* recursively free signatures */
498 static void free_sigs(fp_entry *e){
499 if(e->next)
500 free_sigs(e->next);
501 free(e);
504 /* alloc_sig return a newly allocated copy of *e */
505 static fp_entry *alloc_sig(fp_entry *e)
507 fp_entry *n = calloc(1, sizeof(fp_entry));
508 *n = *e; // copy
509 return n;
512 /* parse the wss field of the signature line */
513 static int parse_sig_wsize(fp_entry *sig, char* w)
515 if (w[0] == '*') {
516 sig->wsize = 1;
517 sig->wsize_mod = MOD_CONST;
518 } else if (tolower(w[0]) == 's') {
519 sig->wsize_mod = MOD_MSS;
520 if (!isdigit(*(w + 1)))
521 fatal("Bad Snn value in WSS in line %d.\n", sig->line);
522 sig->wsize = atoi(w + 1);
523 } else if (tolower(w[0]) == 't') {
524 sig->wsize_mod = MOD_MTU;
525 if (!isdigit(*(w + 1)))
526 fatal("Bad Tnn value in WSS in line %d.\n", sig->line);
527 sig->wsize = atoi(w + 1);
528 } else if (w[0] == '%') {
529 if (!(sig->wsize = atoi(w + 1)))
530 fatal("Null modulo for window size in config line %d.\n",
531 sig->line);
532 sig->wsize_mod = MOD_CONST;
533 } else
534 sig->wsize = atoi(w);
536 return 0;
539 /* parse the option field of the signature line */
540 static int parse_sig_options(fp_entry *sig, char* p)
542 sig->zero_stamp = 1;
544 if (*p == '.')
545 p++;
547 while (*p) {
548 uint8_t optcnt = sig->optcnt;
549 switch (tolower(*p)) {
551 case 'n':
552 sig->opt[optcnt] = TCPOPT_NOP;
553 break;
555 case 'e':
556 sig->opt[optcnt] = TCPOPT_EOL;
557 //if (*(p + 1)) // Old! Improved fingerprints with also collecting options after EOL
558 // fatal("EOL not the last option (line %d).\n", sig->line);
559 break;
561 case 's':
562 sig->opt[optcnt] = TCPOPT_SACKOK;
563 break;
565 case 't':
566 sig->opt[optcnt] = TCPOPT_TIMESTAMP;
567 if (*(p + 1) != '0') {
568 sig->zero_stamp = 0;
569 if (isdigit(*(p + 1)))
570 fatal("Bogus Tstamp specification in line %d.\n",
571 sig->line);
573 break;
575 case 'w':
576 sig->opt[optcnt] = TCPOPT_WSCALE;
577 if (p[1] == '*') {
578 sig->wsc = 1;
579 sig->wsc_mod = MOD_CONST;
580 } else if (p[1] == '%') {
581 if (!(sig->wsc = atoi(p + 2)))
582 fatal
583 ("Null modulo for wscale in config line %d.\n",
584 sig->line);
585 sig->wsc_mod = MOD_CONST;
586 } else if (!isdigit(*(p + 1)))
587 fatal("Incorrect W value in line %d.\n", sig->line);
588 else
589 sig->wsc = atoi(p + 1);
590 break;
592 case 'm':
593 sig->opt[optcnt] = TCPOPT_MAXSEG;
594 if (p[1] == '*') {
595 sig->mss = 1;
596 sig->mss_mod = MOD_CONST;
597 } else if (p[1] == '%') {
598 if (!(sig->mss = atoi(p + 2)))
599 fatal("Null modulo for MSS in config line %d.\n",
600 sig->line);
601 sig->mss_mod = MOD_CONST;
602 } else if (!isdigit(*(p + 1)))
603 fatal("Incorrect M value in line %d.\n", sig->line);
604 else
605 sig->mss = atoi(p + 1);
606 break;
609 * Yuck!
611 case '?':
612 if (!isdigit(*(p + 1)))
613 fatal("Bogus ?nn value in line %d.\n", sig->line);
614 else
615 sig->opt[optcnt] = atoi(p + 1);
616 break;
618 default:
619 fatal("Unknown TCP option '%c' in config line %d.\n", *p,
620 sig->line);
623 if (++sig->optcnt >= MAXOPT)
624 fatal
625 ("Too many TCP options specified in config line %d.\n",
626 sig->line);
629 * Skip separators
631 do {
632 p++;
633 } while (*p && !isalpha(*p) && *p != '?');
635 return 0;
638 /* parse the quirks field of the signature line */
639 static int parse_sig_quirks(fp_entry *sig, uint8_t *p)
641 while (*p){
642 switch (toupper(*(p++))) {
643 case 'E':
644 fatal
645 ("Quirk 'E' (line %d) is obsolete. Remove it, append E to the "
646 "options.\n", sig->line);
648 case 'K':
649 //if (!rst_mode)
650 if (!IS_COSET(&config,CO_RST))
651 fatal("Quirk 'K' (line %d) is valid only in RST+ (-R)"
652 " mode (wrong config file?).\n", sig->line);
653 sig->quirks |= QUIRK_RSTACK;
654 break;
656 case 'D':
657 sig->quirks |= QUIRK_DATA;
658 break;
660 case 'Q':
661 sig->quirks |= QUIRK_SEQEQ;
662 break;
663 case '0':
664 sig->quirks |= QUIRK_SEQ0;
665 break;
666 case 'P':
667 sig->quirks |= QUIRK_PAST;
668 break;
669 case 'Z':
670 sig->quirks |= QUIRK_ZEROID;
671 break;
672 case 'I':
673 sig->quirks |= QUIRK_IPOPT;
674 break;
675 case 'U':
676 sig->quirks |= QUIRK_URG;
677 break;
678 case 'X':
679 sig->quirks |= QUIRK_X2;
680 break;
681 case 'A':
682 sig->quirks |= QUIRK_ACK;
683 break;
684 case 'T':
685 sig->quirks |= QUIRK_T2;
686 break;
687 case 'F':
688 sig->quirks |= QUIRK_FLAGS;
689 break;
690 case 'N':
691 sig->quirks |= QUIRK_FINACK;
692 break;
693 case 'L':
694 sig->quirks |= QUIRK_FLOWL;
695 break;
696 case '!':
697 sig->quirks |= QUIRK_BROKEN;
698 break;
699 case '.':
700 break;
701 default:
702 fatal("Bad quirk '%c' in line %d.\n", *(p - 1), sig->line);
705 return 0;
710 /* load_sigs: fill **sig with fp_entry signatures from *file
712 * sigp is a pointer to either
713 ** a pointer to a preallocated buffer of size max_sigs * fp_entry OR
714 ** a NULL pointer indicating that we should allocate max_sigs for you
715 * max_sigs is the maximal size of the buffer, or 0 in which case we decide
717 * Theory: snarf sigs in serially, easypeasy
718 * Practice: lookups are a bitch and require a buckethash.
719 ** -> store sigs directly into hash.
721 * returns errno
723 int load_sigs(const char *file, fp_entry **sigp[], int hashsize)
725 fp_entry **sig; // output
726 uint32_t ln = 0;
727 //debug("opening %s\n", file);
728 FILE *f = fopen(file, "r");
729 char buf[MAXLINE];
730 char *p;
731 if (!f) {
732 perror("failed to open file");
733 return errno;
735 if(!sigp){
736 perror("need a pointer to fill");
737 return -1;
739 if(!hashsize)
740 hashsize = SIG_HASHSIZE;
741 if(*sigp == NULL){
742 *sigp = calloc(hashsize, sizeof(fp_entry*));
743 sig = *sigp;
746 while ((p = fgets(buf, sizeof(buf), f))) {
747 uint32_t l;
749 char obuf[MAXLINE], genre[MAXLINE], desc[MAXLINE];
750 uint8_t quirks[MAXLINE];
751 char w[MAXLINE], sb[MAXLINE];
752 char *gptr = genre;
753 uint32_t t, d, s;
754 fp_entry asig = {0}; //guarantee it's empty this sig
755 fp_entry *e;
757 ln++;
759 /* Remove leading and trailing blanks */
760 while (isspace(*p))
761 p++;
762 l = strlen(p);
763 while (l && isspace(*(p + l - 1)))
764 *(p + (l--) - 1) = 0;
766 /* Skip empty lines and comments */
767 if (!l)
768 continue;
769 if (*p == '#')
770 continue;
772 if (sscanf
773 (p, "%[0-9%*()ST]:%d:%d:%[0-9()*]:%[^:]:%[^ :]:%[^:]:%[^:]",
774 w, &t, &d, sb, obuf, quirks, genre, desc) != 8)
775 fatal("Syntax error in config line %d.\n", ln);
777 gptr = genre;
779 if (*sb != '*') {
780 s = atoi(sb);
781 } else
782 s = 0;
784 reparse_ptr:
786 switch (*gptr) {
787 case '-':
788 asig.userland = 1;
789 gptr++;
790 goto reparse_ptr;
791 case '*':
792 asig.no_detail = 1;
793 gptr++;
794 goto reparse_ptr;
795 case '@':
796 asig.generic = 1;
797 gptr++;
798 //gencnt++;
799 goto reparse_ptr;
800 case 0:
801 fatal("Empty OS genre in line %d.\n", ln);
804 asig.os = strdup(gptr);
805 asig.desc = strdup(desc);
806 asig.ttl = t;
807 asig.size = s;
808 asig.df = d;
810 parse_sig_wsize(&asig, w);
811 asig.line = ln;
812 parse_sig_options(&asig, obuf);
813 parse_sig_quirks(&asig, quirks);
814 uint32_t index = SIGHASH(s, asig.optcnt, asig.quirks, d) % hashsize;
815 e = sig[index];
817 if (!e) {
818 sig[index] = alloc_sig(&asig);
819 } else {
820 int cc = 0;
821 // collision!
822 while (e->next){
823 e = e->next;
824 cc++;
827 fprintf(stderr, "hash collision %d: \n%d: %s - %s\n%d: %s - %s\n",
828 cc, asig.line, asig.os, asig.desc, e->line, e->os, e->desc);
830 e->next = alloc_sig(&asig);
834 if (check_collide)
835 collide(sigcnt);
839 if (++sigcnt >= hashsize)
840 fatal("Maximum signature count exceeded.\n");
845 fclose(f);
846 #ifdef DUMP_SIG_HASH
848 int i;
849 for (i = 0; i < sigcnt; i++) {
850 print_sig(&sig[i]);
853 #endif
854 #ifdef DEBUG_HASH
856 int i;
857 fp_entry *p;
858 printf("Hash table layout: ");
859 for (i = 0; i < hashsize; i++) {
860 int z = 0;
861 p = sig[i];
862 while (p) {
863 p = p->next;
864 z++;
866 printf("%d ", z);
868 putchar('\n');
870 #endif /* DEBUG_HASH */
872 if (check_collide)
873 debug("[+] Signature collision check successful.\n");
876 if (!sigcnt)
877 debug("[!] WARNING: no signatures loaded from config file.\n");
880 return 0;
883 /* run through the hash, free entries, then free hash */
884 void unload_sigs(fp_entry **sigp, int size)
886 int i = size;
887 fp_entry *e;
888 while(i--){
889 e = sigp[i];
890 if (e)
891 free_sigs(e);
892 sigp[i] = NULL; // clear
894 free(*sigp);
895 *sigp = NULL;
900 /* a dns cache of one? */
901 #define MY_MAXDNS 32
903 #include <netdb.h>
904 static inline char* grab_name(uint8_t* a) {
905 struct hostent* r;
906 static char rbuf[MY_MAXDNS+6] = "/";
907 uint32_t j;
908 char *s,*d = rbuf+1;
910 if (!do_resolve) return "";
911 r = gethostbyaddr(a,4,AF_INET);
912 if (!r || !(s = r->h_name) || !(j = strlen(s))) return "";
913 if (j > MY_MAXDNS) return "";
915 while (j--) {
916 if (isalnum(*s) || *s == '-' || *s == '.') *d = *s;
917 else *d = '?';
918 d++; s++;
921 *d=0;
923 return rbuf;
929 char* lookup_link(uint16_t mss, char txt) {
930 uint32_t i;
931 static char tmp[32];
933 if (!mss) return txt ? "unspecified" : 0;
934 mss += 40;
936 for (i=0;i<MTU_CNT;i++) {
937 if (mss == mtu[i].mtu) return mtu[i].dev;
938 if (mss < mtu[i].mtu) goto unknown;
941 unknown:
943 if (!txt) return 0;
944 sprintf(tmp,"unknown-%d",mss);
945 return tmp;
950 static char* lookup_tos(uint8_t t) {
951 uint32_t i;
953 if (!t) return 0;
955 for (i=0;i<TOS_CNT;i++) {
956 if (t == tos[i].tos) return tos[i].desc;
957 if (t < tos[i].tos) break;
960 return 0;
965 void dump_packet(const uint8_t* pkt,uint16_t plen) {
966 uint32_t i;
967 uint8_t tbuf[PKT_DLEN+1];
968 uint8_t* t = tbuf;
970 for (i=0;i<plen;i++) {
971 uint8_t c = *(pkt++);
972 if (!(i % PKT_DLEN)) dlog(" [%02x] ",i);
973 dlog("%02x ",c);
974 *(t++) = isprint(c) ? c : '.';
975 if (!((i+1) % PKT_DLEN)) {
976 *t=0;
977 dlog(" | %s\n",(t=tbuf));
981 if (plen % PKT_DLEN) {
982 *t=0;
983 while (plen++ % PKT_DLEN) dlog(" ");
984 dlog(" | %s\n",tbuf);
990 void dump_payload(const uint8_t* data,uint16_t dlen) {
991 uint8_t tbuf[PKT_MAXPAY+2];
992 uint8_t* t = tbuf;
993 uint8_t i;
994 uint8_t max = dlen > PKT_MAXPAY ? PKT_MAXPAY : dlen;
996 if (!dlen) return;
998 for (i=0;i<max;i++) {
999 if (isprint(*data)) *(t++) = *data;
1000 else if (!*data) *(t++) = '?';
1001 else *(t++) = '.';
1002 data++;
1005 *t = 0;
1007 plog( " # Payload: \"%s\"%s",tbuf,dlen > PKT_MAXPAY ? "...\n" : "\n");
1012 /* parse TCP packet quirks */
1013 static inline void parse_quirks(uint8_t ftype, tcp_header *tcph, uint32_t *quirks)
1015 if (ftype == TF_RST && (tcph->t_flags & TF_ACK))
1016 *quirks |= QUIRK_RSTACK;
1017 if (ftype == TF_FIN && (tcph->t_flags & TF_ACK))
1018 *quirks |= QUIRK_FINACK;
1020 if (tcph->t_seq == tcph->t_ack)
1021 *quirks |= QUIRK_SEQEQ;
1022 if (!tcph->t_seq)
1023 *quirks |= QUIRK_SEQ0;
1024 // ftype makes little sense here
1025 if (tcph->t_flags & ~(TF_SYN | TF_ACK | TF_RST | TF_ECE | TF_CWR
1026 | ((ftype == TF_ACK)? TF_PUSH : 0)))
1027 *quirks |= QUIRK_FLAGS;
1028 if (tcph->t_ack)
1029 *quirks |= QUIRK_ACK;
1030 if (tcph->t_urgp)
1031 *quirks |= QUIRK_URG;
1032 if (TCP_X2(tcph))
1033 *quirks |= QUIRK_X2;
1035 /* parse TCP option header field
1036 * yes, this function returns the timestamp for now */
1037 static inline uint32_t parse_tcpopt(const uint8_t *opt_ptr, int32_t ilen, const uint8_t *end_ptr, fp_entry *e)
1039 uint8_t ocnt = 0;
1040 int32_t olen;
1041 // mnemonics
1042 uint32_t *quirks = &e->quirks;
1043 uint8_t *op = e->opt;
1044 // timestamp is 64bit, but see if I care
1045 uint32_t tstamp = 0;
1047 while (ilen > 0) {
1048 ilen--;
1050 // * let the phun begin...
1051 switch (*(opt_ptr++)) {
1052 case TCPOPT_EOL:
1053 // * EOL
1054 op[ocnt] = TCPOPT_EOL;
1056 if (ilen) {
1057 *quirks |= QUIRK_PAST;
1059 break;
1061 case TCPOPT_NOP:
1062 // * NOP
1063 op[ocnt] = TCPOPT_NOP;
1064 break;
1066 case TCPOPT_SACKOK:
1067 // * SACKOK LEN
1068 op[ocnt] = TCPOPT_SACKOK;
1069 ilen--;
1070 opt_ptr++;
1071 break;
1073 case TCPOPT_MAXSEG:
1074 // * MSS LEN D0 D1
1075 if (opt_ptr + 3 > end_ptr) {
1076 borken:
1077 *quirks |= QUIRK_BROKEN;
1078 goto end_parsing;
1080 op[ocnt] = TCPOPT_MAXSEG;
1081 e->mss = GET16(opt_ptr + 1);
1082 ilen -= 3;
1083 opt_ptr += 3;
1084 break;
1086 case TCPOPT_WSCALE:
1087 // * WSCALE LEN D0
1088 if (opt_ptr + 2 > end_ptr)
1089 goto borken;
1090 op[ocnt] = TCPOPT_WSCALE;
1091 e->wsc = *(uint8_t *) (opt_ptr + 1);
1092 ilen -= 2;
1093 opt_ptr += 2;
1094 break;
1096 case TCPOPT_TIMESTAMP:
1097 // * TSTAMP LEN T0 T1 T2 T3 A0 A1 A2 A3
1098 // ugly handling of a beautiful 64bit field
1099 if (opt_ptr + 9 > end_ptr)
1100 goto borken;
1101 op[ocnt] = TCPOPT_TIMESTAMP;
1103 memcpy(&tstamp, opt_ptr + 5, 4);
1104 if (tstamp)
1105 *quirks |= QUIRK_T2;
1107 memcpy(&tstamp, opt_ptr + 1, 4);
1108 tstamp = ntohl(tstamp);
1110 ilen -= 9;
1111 opt_ptr += 9;
1112 break;
1113 case TCPOPT_PROXBLUECOAT:
1114 case TCPOPT_PROXCISCO:
1115 case TCPOPT_PROXRIVERBED1:
1116 case TCPOPT_PROXRIVERBED2:
1117 dlog("magic middleware option %02x detected", *(opt_ptr - 1) );
1118 // fallthru for now..
1119 default:
1120 // * Hrmpf...
1121 if (opt_ptr + 1 > end_ptr)
1122 goto borken;
1124 op[ocnt] = *(opt_ptr - 1);
1125 olen = *(uint8_t *) (opt_ptr) - 1;
1126 if (olen > 32 || (olen < 0))
1127 goto borken;
1129 ilen -= olen;
1130 opt_ptr += olen;
1131 break;
1134 ocnt++;
1135 if (ocnt >= MAXOPT - 1)
1136 goto borken;
1138 // * Whoops, we're past end_ptr
1139 if (ilen > 0)
1140 if (opt_ptr >= end_ptr)
1141 goto borken;
1144 end_parsing:
1145 e->optcnt = ocnt;
1146 return tstamp;
1150 /* find_match(): lookup packet with fingerprint e and info pi in sighash sig[]
1152 * match is returned as e->os and e->desc in e
1153 * NB NOTE XXX: the os and desc fields are statically allocated, do not free()!
1155 fp_entry *find_match(
1156 fp_entry *sig[], uint32_t hashsize,
1157 fp_entry *e, packetinfo *pi,
1158 uint32_t tstamp,
1159 uint8_t plen,
1160 uint8_t *pay
1161 /* uses the following values
1162 // uint16_t tot // e->size
1163 // uint8_t df, // e->
1164 // uint8_t ttl,
1165 // uint16_t wss, // wsize
1166 // uint32_t src, // pi->ip_src
1167 // uint32_t dst, // pi
1168 // uint16_t sp, // ntohs(pi->tcph->src_port)
1169 // uint16_t dp,
1170 // uint8_t ocnt, // optcnt
1171 // uint8_t* op, // opt
1172 // uint16_t mss,
1173 // uint8_t wsc,
1174 // uint32_t tstamp, ****
1175 // uint8_t tos, // pi->ip4->ip_tos
1176 // uint32_t quirks, // e
1177 // uint8_t ecn, // pi->tcph->t_flags & (TF_ECE|TF|CWR) // oh really?
1178 // uint8_t* pkt, // pi->ip4
1183 uint32_t j;
1184 uint8_t nat=0;
1185 fp_entry* p;
1186 uint8_t orig_df = e->df;
1187 char* tos_desc = 0;
1189 fp_entry* fuzzy = 0;
1190 uint8_t fuzzy_now = 0;
1191 char outbuf[INET_ADDRSTRLEN+1];
1193 //if ( sig == config.sig_ack ) e->optcnt = 3;
1195 re_lookup:
1197 p = sig[SIGHASH(e->size,e->optcnt,e->quirks,e->df) % hashsize];
1199 if (PI_IP4(pi)) tos_desc = lookup_tos(PI_TOS(pi));
1201 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1202 while (p) {
1204 /* Cheap and specific checks first... */
1205 // esize == 0 => open_mode
1206 if(e->size){
1207 /* psize set to zero means >= PACKET_BIG */
1208 if (p->size) { if (e->size ^ p->size) { p = p->next; continue; } }
1209 else if (e->size < PACKET_BIG) { p = p->next; continue; }
1212 if (e->optcnt ^ p->optcnt) { p = p->next; continue; }
1214 if (p->zero_stamp ^ (!tstamp)) { p = p->next; continue; }
1215 if (p->df ^ e->df) { p = p->next; continue; }
1216 if (p->quirks ^ e->quirks) { p = p->next; continue; }
1218 /* Check e->mss and WSCALE... */
1219 if (!p->mss_mod) {
1220 if (e->mss ^ p->mss) { p = p->next; continue; }
1221 } else if (e->mss % p->mss) { p = p->next; continue; }
1223 if (!p->wsc_mod) {
1224 if (e->wsc ^ p->wsc) { p = p->next; continue; }
1225 } else if (e->wsc % p->wsc) { p = p->next; continue; }
1227 /* Then proceed with the most complex e->wsize check... */
1228 switch (p->wsize_mod) {
1229 case 0:
1230 if (e->wsize ^ p->wsize) { p = p->next; continue; }
1231 break;
1232 case MOD_CONST:
1233 if (e->wsize % p->wsize) { p = p->next; continue; }
1234 break;
1235 case MOD_MSS:
1236 if (e->mss && !(e->wsize % e->mss)) {
1237 if ((e->wsize / e->mss) ^ p->wsize) { p = p->next; continue; }
1238 } else if (!(e->wsize % 1460)) {
1239 if ((e->wsize / 1460) ^ p->wsize) { p = p->next; continue; }
1240 } else { p = p->next; continue; }
1241 break;
1242 case MOD_MTU:
1243 if (e->mss && !(e->wsize % (e->mss+40))) {
1244 if ((e->wsize / (e->mss+40)) ^ p->wsize) { p = p->next; continue; }
1245 } else if (!(e->wsize % 1500)) {
1246 if ((e->wsize / 1500) ^ p->wsize) { p = p->next; continue; }
1247 } else { p = p->next; continue; }
1248 break;
1251 /* Numbers agree. Let's check options */
1253 for (j=0;j<e->optcnt;j++){
1254 if (p->opt[j] ^ e->opt[j]) goto continue_search;
1257 /* Check TTLs last because we might want to go fuzzy. */
1258 if (p->ttl < e->ttl) {
1259 if (use_fuzzy) fuzzy = p;
1260 p = p->next;
1261 continue;
1264 /* Naah... can't happen ;-) */
1265 if (!p->no_detail){
1266 if (p->ttl - e->ttl > MAXDIST) {
1267 if (use_fuzzy) fuzzy = p;
1268 p = p->next;
1269 continue;
1273 continue_fuzzy:
1275 /* Match! */
1277 if (e->mss & e->wsize) {
1278 if (p->wsize_mod == MOD_MSS) {
1279 if ((e->wsize % e->mss) && !(e->wsize % 1460)) nat=1;
1280 } else if (p->wsize_mod == MOD_MTU) {
1281 if ((e->wsize % (e->mss+40)) && !(e->wsize % 1500)) nat=2;
1285 if (!no_known) {
1287 // What about IPv6?
1289 // copy in the os/desc pointers. These are not to be free()d!
1290 e->os = p->os;
1291 e->desc = p->desc;
1294 /* TODO:many verbose checks could be made into os fields */
1295 if( config.verbose > 1 ){
1296 u_ntop_src(pi, outbuf);
1298 olog("%s:%d - %s ",outbuf, PI_TCP_SP(pi),p->os);
1300 if (!no_osdesc) olog("%s ",p->desc);
1301 if (nat == 1){
1302 olog("(NAT!) ");
1303 } else {
1304 if (nat == 2) olog("(NAT2!) ");
1307 if (PI_ECN(pi)) olog("(ECN) ");
1308 if (orig_df ^ e->df) olog("(firewall!) ");
1310 if (pi->ip4 && PI_TOS(pi)) {
1311 if (tos_desc) olog("[%s] ",tos_desc); else olog("[tos %d] ",PI_TOS(pi));
1313 if (p->no_detail) olog("* "); else
1314 if (tstamp) olog("(up: %d hrs) ",tstamp/360000);
1316 if (always_sig || (p->generic && !no_unknown)) {
1318 if (!mode_oneline) olog("\n ");
1319 olog("Signature: [");
1321 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1323 if (p->generic)
1324 olog(":%s:?] ",p->os);
1325 else
1326 olog("] ");
1329 if (!no_extra && !p->no_detail) {
1330 if (!mode_oneline) olog("\n ");
1332 u_ntop_dst(pi, outbuf);
1335 if (fuzzy_now)
1336 olog("-> %s:%d (link: %s)",outbuf, PI_TCP_DP(pi),
1337 lookup_link(e->mss,1));
1338 else
1339 olog("-> %s:%d (distance %d, link: %s)",outbuf, PI_TCP_DP(pi),
1340 p->ttl - e->ttl,
1341 lookup_link(e->mss,1));
1343 if (p->generic) olog("[GENERIC] ");
1344 if (fuzzy_now) olog("[FUZZY] ");
1345 olog("\n");
1348 if (pay && payload_dump) dump_payload(pay,plen - (pay - (uint8_t*)PI_IP4(pi)));
1350 if (full_dump) dump_packet((uint8_t*)PI_IP4(pi),plen);
1354 /* find masquerade code... where is the sauce?
1355 if (find_masq && !p->userland) {
1356 int16_t sc = p0f_findmasq(src,p->os,(p->no_detail || fuzzy_now) ? -1 :
1357 (p->ttl - e->ttl), e->mss, nat, orig_df ^ e->df,p-sig,
1358 tstamp ? tstamp / 360000 : -1);
1359 a=(uint8_t*)& PI_IP4SRC(pi);
1360 if (sc > masq_thres) {
1361 printf(">> Masquerade at %u.%u.%u.%u%s: indicators at %d%%.",
1362 a[0],a[1],a[2],a[3],grab_name(a),sc);
1363 if (!mode_oneline) putchar('\n'); else printf(" -- ");
1364 if (masq_flags) {
1365 printf(" Flags: ");
1366 p0f_descmasq();
1367 putchar('\n');
1372 if (use_cache || find_masq)
1373 p0f_addcache(src,dst,sp,dp,p->os,p->desc,(p->no_detail || fuzzy_now) ?
1374 -1 : (p->ttl - e->ttl),p->no_detail ? 0 : lookup_link(e->mss,0),
1375 tos_desc, orig_df ^ e->df, nat, !p->userland, e->mss, p-sig,
1376 tstamp ? tstamp / 360000 : -1);
1379 fflush(0);
1381 return e;
1383 continue_search:
1385 p = p->next;
1389 if (!e->df) { e->df = 1; goto re_lookup; }
1391 if (use_fuzzy && fuzzy) {
1392 e->df = orig_df;
1393 fuzzy_now = 1;
1394 p = fuzzy;
1395 fuzzy = 0;
1396 goto continue_fuzzy;
1399 if (e->mss & e->wsize) {
1400 if ((e->wsize % e->mss) && !(e->wsize % 1460)) nat=1;
1401 else if ((e->wsize % (e->mss+40)) && !(e->wsize % 1500)) nat=2;
1404 if (!no_unknown) {
1405 u_ntop_src(pi, outbuf);
1406 vlog(2,"%s:%d - UNKNOWN [:?:?]",outbuf,PI_TCP_SP(pi));
1408 //display_signature(e->ttl,e->size,orig_df,e->opt,e->optcnt,e->mss,e->wsize,e->wsc,tstamp,e->quirks);
1410 if (rst_mode) {
1412 /* Display a reasonable diagnosis of the RST+ACK madness! */
1414 switch (e->quirks & (QUIRK_RSTACK | QUIRK_SEQ0 | QUIRK_ACK)) {
1416 /* RST+ACK, SEQ=0, ACK=0 */
1417 case QUIRK_RSTACK | QUIRK_SEQ0:
1418 vlog(2, "(invalid-K0) "); break;
1420 /* RST+ACK, SEQ=0, ACK=n */
1421 case QUIRK_RSTACK | QUIRK_ACK | QUIRK_SEQ0:
1422 vlog(2, "(refused) "); break;
1424 /* RST+ACK, SEQ=n, ACK=0 */
1425 case QUIRK_RSTACK:
1426 vlog(2, "(invalid-K) "); break;
1428 /* RST+ACK, SEQ=n, ACK=n */
1429 case QUIRK_RSTACK | QUIRK_ACK:
1430 vlog(2, "(invalid-KA) "); break;
1432 /* RST, SEQ=n, ACK=0 */
1433 case 0:
1434 vlog(2, "(dropped) "); break;
1436 /* RST, SEQ=m, ACK=n */
1437 case QUIRK_ACK:
1438 vlog(2, "(dropped 2) "); break;
1440 /* RST, SEQ=0, ACK=0 */
1441 case QUIRK_SEQ0:
1442 vlog(2, "(invalid-0) "); break;
1444 /* RST, SEQ=0, ACK=n */
1445 case QUIRK_ACK | QUIRK_SEQ0:
1446 vlog(2, "(invalid-0A) "); break;
1452 if (nat == 1) vlog(2, "(NAT!) ");
1453 else if (nat == 2) vlog(2, "(NAT2!) ");
1455 if (PI_ECN(pi)) vlog(2, "(ECN) ");
1457 if (pi->ip4 && PI_TOS(pi)) {
1458 if (tos_desc) vlog(2, "[%s] ",tos_desc); else vlog(2, "[tos %d] ",PI_TOS(pi));
1461 if (tstamp) vlog(2, "(up: %d hrs) ",tstamp/360000);
1463 if (!no_extra) {
1464 u_ntop_dst(pi, outbuf);
1465 //if (!mode_oneline) dlog("\n ");
1466 vlog(2, "-> %s:%d (link: %s)", outbuf,
1467 PI_TCP_DP(pi),lookup_link(e->mss,1));
1471 if (use_cache)
1472 p0f_addcache(src,dst,PI_TCP_SP(pi),PI_TCP_DP(pi),0,0,-1,lookup_link(e->mss,0),tos_desc,
1473 0,nat,0 // not real, we're not sure
1474 ,e->mss,(uint32_t)-1,
1475 tstamp ? tstamp / 360000 : -1);
1477 vlog(2, "\n");
1479 if (pay && payload_dump) dump_payload(pay,plen - (pay - (uint8_t*)PI_IP4(pi)));
1480 //putchar('\n'); //edward
1481 if (full_dump) dump_packet((uint8_t*)PI_IP4(pi),plen);
1482 fflush(0);
1486 return e;
1490 // pass the pointers
1491 // unresolved: pass the packet?
1493 static inline void find_match_e(fp_entry *e, uint32_t tstamp, void *packet)
1495 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);
1500 /* my ideal interface
1501 fp_entry *lookup_sig(fp_entry sig[], packetinfo *pi)
1503 fp_entry *e = bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)];
1505 if (!e) {
1506 bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)] =
1507 sig + sigcnt;
1508 } else {
1509 while (e->next)
1510 e = e->next;
1511 e->next = sig + sigcnt;
1515 fp_entry *fp_tcp(packetinfo *pi, uint8_t ftype)
1517 uint8_t *opt_ptr;
1518 const uint8_t * end_ptr;
1519 uint8_t *payload = 0;
1520 fp_entry e = { 0 };
1521 int32_t ilen;
1522 uint32_t tstamp = 0;
1524 /* * If the declared length is shorter than the snapshot (etherleak
1525 * or such), truncate the package.
1526 * These tests are IP-specific and should one day go into into IP preproc*/
1527 end_ptr = pi->end_ptr;
1528 switch(pi->af){
1529 case AF_INET6:
1530 opt_ptr = (uint8_t *) pi->ip6 + IP6_HEADER_LEN + ntohs(pi->ip6->len); //*
1531 if (end_ptr > opt_ptr)
1532 end_ptr = opt_ptr;
1533 // If IP header ends past end_ptr
1534 if ((uint8_t *) (pi->ip6 + 1) > end_ptr)
1535 return NULL;
1536 if (IP6_FL(pi->ip6)) {
1537 /* http://tools.ietf.org/html/rfc2460#page-25
1538 The Flow Label field may be used by a source to label sequences of
1539 packets for which it requests special handling by the IPv6 routers.
1540 Mostly Zero today - subject to change in the future...
1541 Maybe parse_ipv6_fl() one day ?
1543 e.quirks |= QUIRK_FLOWL;
1545 e.ttl = pi->ip6->hop_lmt;
1546 e.size = (ftype == TF_ACK) ? 0 : ntohs(pi->ip6->len);
1547 e.df = 1; // for now
1548 if (!IP6_FL(pi->ip6)) //*
1549 e.quirks |= QUIRK_ZEROID;
1550 break;
1551 case AF_INET:
1552 opt_ptr = (uint8_t *) pi->ip4 + ntohs(pi->ip4->ip_len); // fixed from htons
1553 if (end_ptr > opt_ptr)
1554 end_ptr = opt_ptr;
1555 if ((uint8_t *) (pi->ip4 + 1) > end_ptr)
1556 return NULL;
1557 ilen = pi->ip4->ip_vhl & 15;
1559 /* * B0rked packet */
1560 if (ilen < 5)
1561 return NULL;
1563 if (ilen > 5) {
1564 e.quirks |= QUIRK_IPOPT;
1566 e.ttl = pi->ip4->ip_ttl;
1567 e.size = (ftype == TF_ACK) ? 0 : ntohs(pi->ip4->ip_len);
1568 e.df = (ntohs(pi->ip4->ip_off) & IP_DF) != 0;
1569 if (!pi->ip4->ip_id)
1570 e.quirks |= QUIRK_ZEROID;
1571 break;
1572 // default: there is no default
1573 default:
1574 fprintf(stderr, "tcp_fp: something very unsafe happened!\n");
1575 return NULL;
1577 //printf("\nend_ptr:%u opt_ptr:%u",end_ptr,opt_ptr);
1579 parse_quirks(ftype,pi->tcph,&e.quirks);
1580 ilen = (TCP_OFFSET(pi->tcph) << 2) - TCP_HEADER_LEN;
1582 opt_ptr = (uint8_t *) (pi->tcph + 1);
1583 if ((uint8_t *) opt_ptr + ilen < end_ptr) {
1584 if (ftype != TF_ACK)
1585 e.quirks |= QUIRK_DATA;
1586 payload = opt_ptr + ilen;
1588 tstamp = parse_tcpopt(opt_ptr, ilen, pi->end_ptr, &e);
1589 //if (!tstamp) e.zero_stamp = 1;
1591 e.wsize = ntohs(pi->tcph->t_win);
1593 //if (pi->ip6 != NULL) return NULL; // Fix this when find_match() is IPv6 aware
1595 // match = find_match(sigs, pi, e);
1596 // ---> after match_network but before update_asset
1597 // find_match(pi, e);
1598 // return this into asset engine
1599 fp_entry **sig = NULL;
1600 if (ftype == CO_SYN) {
1601 sig=config.sig_syn;
1602 } else if (ftype == CO_SYNACK) {
1603 sig=config.sig_synack;
1604 } else if (ftype == CO_RST) {
1605 sig=config.sig_rst;
1606 } else if (ftype == CO_FIN) {
1607 sig=config.sig_fin;
1608 } else if (ftype == CO_ACK) {
1609 sig=config.sig_ack;
1613 fp_entry *match = NULL;
1614 if (sig != NULL) {
1615 match = find_match(sig,
1616 config.sig_hashsize,
1618 pi, // pass all packet characteristics
1619 tstamp,
1620 end_ptr - (uint8_t *) pi->ip4,
1621 payload
1625 //if (match->os != NULL) memcpy(&e.next->os, match->os, MAXLINE);
1626 //if (match->desc != NULL) memcpy(&e.next->desc, match->desc, MAXLINE);
1627 update_asset_os(pi, ftype, NULL, &e, tstamp);
1628 return NULL; // can't return stack-allocated * fp_entry e;
1630 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),
1631 IP6_V(ip6),ntohs(IP6_TC(ip6)),
1632 ntohs(IP6_FL(ip6)),
1633 mss_val, ntohs(tcph->t_win));
1637 // /* sp */ ntohs(tcph->sport),
1638 // /* dp */ ntohs(tcph->dport),
1639 // /* ocnt */ ocnt,
1640 // /* op */ op,
1641 // /* mss */ mss_val,
1642 // /* wsc */ wsc_val,
1643 // /* tst */ tstamp,
1644 // /* TOS */ iph->tos,
1645 // /* Q? */ quirks,
1646 // /* ECN */ tcph->flags & (TH_ECE|TH_CWR),
1647 // /* pkt */ (_u8*)iph,
1648 // /* len */ end_ptr - (_u8*)iph,
1649 // /* pay */ pay,
1650 // /* ts */ pts
1651 // );
1657 void dump_sigs(fp_entry *mysig[], int max)
1659 int i;
1660 for (i = 0; i < max; i++){
1661 if (!mysig[i] || !mysig[i]->os)
1662 continue;
1663 print_sigs(mysig[i]);
1668 #ifdef SIG_STANDALONE
1669 #define HSIZE 241
1670 int main(int argc, char **argv)
1673 fp_entry **siga[16] = {0};
1674 int i = 0;
1675 if (argc < 2) {
1676 fprintf(stderr, "Where are my sigs?\n");
1677 exit(1);
1679 while (--argc) {
1680 argv++;
1681 load_sigs(*argv, &siga[i], HSIZE);
1682 dump_sigs(siga[i], HSIZE);
1683 unload_sigs(siga[i], HSIZE);
1688 #endif