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) ***
19 load_sigs() <- create hashtable from file
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
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);
53 extern globalconfig config
;
56 #define SIG_HASHSIZE 1024
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
;
78 static uint8_t no_extra
,
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
)
93 bstring fp
= bformat("");
94 for (j
= 0; j
< ocnt
; j
++) {
100 bformata(fp
, "W%d", wsc
);
103 bformata(fp
, "M%d", mss
);
105 case TCPOPT_TIMESTAMP
:
117 bformata(fp
, "?%d", op
[j
]);
130 bstring
gen_fp_tcpquirks(uint32_t quirks
)
132 bstring fp
= bformat("");
136 if (quirks
& QUIRK_RSTACK
)
138 if (quirks
& QUIRK_SEQEQ
)
140 if (quirks
& QUIRK_SEQ0
)
142 if (quirks
& QUIRK_PAST
)
144 if (quirks
& QUIRK_ZEROID
)
146 if (quirks
& QUIRK_IPOPT
)
148 if (quirks
& QUIRK_URG
)
150 if (quirks
& QUIRK_X2
)
152 if (quirks
& QUIRK_ACK
)
154 if (quirks
& QUIRK_T2
)
156 if (quirks
& QUIRK_FLAGS
)
158 if (quirks
& QUIRK_DATA
)
162 if (quirks
& QUIRK_FINACK
)
164 if (quirks
& QUIRK_FLOWL
)
167 if (quirks
& QUIRK_BROKEN
)
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
)
193 uint16_t mss
, wss
, tot
;
195 bstring fp
, fpopt
, fpquirks
;
201 ttl
= e
->ttl
; //normalize_ttl(e->ttl);
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)");
216 bformata(fp
, "%d", wss
);
219 if ( tf
== TF_ACK
|| tf
== TF_RST
) {
220 bformata(fp
, ":%d:%d:*:",ttl
, e
->df
);
222 if (e
->size
< PACKET_BIG
)
223 bformata(fp
, ":%d:%d:%d:", ttl
, e
->df
, e
->size
);
225 bformata(fp
, ":%d:%d:*(%d):", ttl
, e
->df
, e
->size
);
229 fpopt
= gen_fp_tcpopt(( tf
== TF_ACK
? TCPOPT_LIMIT
: e
->optcnt
), e
->opt
, mss
, wss
, e
->wsc
, tstamp
);
236 fpquirks
= gen_fp_tcpquirks(e
->quirks
);
237 bconcat(fp
, fpquirks
);
240 //if (tstamp) printf("(* uptime: %d hrs)\n",tstamp/360000);
241 //update_asset_os(pi, tf, fp, tstamp?tstamp:0);
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
, '-');
254 printf("],%s:%s\n", e
->os
, e
->desc
);
256 void print_sigs(fp_entry
* e
)
264 static void collide(uint32_t id)
269 if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30) {
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)) {
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)
290 if (sig[id].df ^ sig[i].df)
292 if (sig[id].zero_stamp ^ sig[i].zero_stamp)
295 // * Zero means >= PACKET_BIG
297 if (sig[id].size ^ sig[i].size)
299 } else if (sig[i].size < PACKET_BIG)
302 if (sig[id].optcnt ^ sig[i].optcnt)
304 if (sig[id].quirks ^ sig[i].quirks)
307 switch (sig[id].wsize_mod) {
309 case 0: // Current: 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)
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)
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)
339 case MOD_MTU: // Current: const, prev: mod MTU
342 || sig[i].wsize * ((sig[i].mss ? sig[i].mss : 1460) +
352 case 1: // Current signature is modulo something
354 // A problem only if this modulo is a multiple of the
357 if (sig[i].wsize_mod != MOD_CONST)
359 if (sig[id].wsize % sig[i].wsize)
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
372 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
373 if (!sig[id].mss_mod) {
375 (sig[id].mss ? sig[id].mss : 1460) * sig[id].wsize;
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) {
388 ((sig[id].mss ? sig[id].mss : 1460) +
400 switch (sig[id].wsc_mod) {
402 case 0: // Current: const
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)
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)
426 case MOD_CONST: // Current signature is modulo something
428 // A problem only if this modulo is a multiple of the
433 if (sig[id].wsc % sig[i].wsc)
441 switch (sig[id].mss_mod) {
443 case 0: // Current: const
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)
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)
467 case MOD_CONST: // Current signature is modulo something
469 // A problem only if this modulo is a multiple of the
473 if ((sig[id].mss ? sig[id].mss : 1460) %
474 (sig[i].mss ? sig[i].mss : 1460))
481 // Now check option sequence
482 for (j = 0; j < sig[id].optcnt; j++)
483 if (sig[id].opt[j] ^ sig[i].opt[j])
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);
497 /* recursively free signatures */
498 static void free_sigs(fp_entry
*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
));
512 /* parse the wss field of the signature line */
513 static int parse_sig_wsize(fp_entry
*sig
, char* w
)
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",
532 sig
->wsize_mod
= MOD_CONST
;
534 sig
->wsize
= atoi(w
);
539 /* parse the option field of the signature line */
540 static int parse_sig_options(fp_entry
*sig
, char* p
)
548 uint8_t optcnt
= sig
->optcnt
;
549 switch (tolower(*p
)) {
552 sig
->opt
[optcnt
] = TCPOPT_NOP
;
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);
562 sig
->opt
[optcnt
] = TCPOPT_SACKOK
;
566 sig
->opt
[optcnt
] = TCPOPT_TIMESTAMP
;
567 if (*(p
+ 1) != '0') {
569 if (isdigit(*(p
+ 1)))
570 fatal("Bogus Tstamp specification in line %d.\n",
576 sig
->opt
[optcnt
] = TCPOPT_WSCALE
;
579 sig
->wsc_mod
= MOD_CONST
;
580 } else if (p
[1] == '%') {
581 if (!(sig
->wsc
= atoi(p
+ 2)))
583 ("Null modulo for wscale in config line %d.\n",
585 sig
->wsc_mod
= MOD_CONST
;
586 } else if (!isdigit(*(p
+ 1)))
587 fatal("Incorrect W value in line %d.\n", sig
->line
);
589 sig
->wsc
= atoi(p
+ 1);
593 sig
->opt
[optcnt
] = TCPOPT_MAXSEG
;
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",
601 sig
->mss_mod
= MOD_CONST
;
602 } else if (!isdigit(*(p
+ 1)))
603 fatal("Incorrect M value in line %d.\n", sig
->line
);
605 sig
->mss
= atoi(p
+ 1);
612 if (!isdigit(*(p
+ 1)))
613 fatal("Bogus ?nn value in line %d.\n", sig
->line
);
615 sig
->opt
[optcnt
] = atoi(p
+ 1);
619 fatal("Unknown TCP option '%c' in config line %d.\n", *p
,
623 if (++sig
->optcnt
>= MAXOPT
)
625 ("Too many TCP options specified in config line %d.\n",
633 } while (*p
&& !isalpha(*p
) && *p
!= '?');
638 /* parse the quirks field of the signature line */
639 static int parse_sig_quirks(fp_entry
*sig
, uint8_t *p
)
642 switch (toupper(*(p
++))) {
645 ("Quirk 'E' (line %d) is obsolete. Remove it, append E to the "
646 "options.\n", sig
->line
);
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
;
657 sig
->quirks
|= QUIRK_DATA
;
661 sig
->quirks
|= QUIRK_SEQEQ
;
664 sig
->quirks
|= QUIRK_SEQ0
;
667 sig
->quirks
|= QUIRK_PAST
;
670 sig
->quirks
|= QUIRK_ZEROID
;
673 sig
->quirks
|= QUIRK_IPOPT
;
676 sig
->quirks
|= QUIRK_URG
;
679 sig
->quirks
|= QUIRK_X2
;
682 sig
->quirks
|= QUIRK_ACK
;
685 sig
->quirks
|= QUIRK_T2
;
688 sig
->quirks
|= QUIRK_FLAGS
;
691 sig
->quirks
|= QUIRK_FINACK
;
694 sig
->quirks
|= QUIRK_FLOWL
;
697 sig
->quirks
|= QUIRK_BROKEN
;
702 fatal("Bad quirk '%c' in line %d.\n", *(p
- 1), sig
->line
);
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.
723 int load_sigs(const char *file
, fp_entry
**sigp
[], int hashsize
)
725 fp_entry
**sig
; // output
727 //debug("opening %s\n", file);
728 FILE *f
= fopen(file
, "r");
732 perror("failed to open file");
736 perror("need a pointer to fill");
740 hashsize
= SIG_HASHSIZE
;
742 *sigp
= calloc(hashsize
, sizeof(fp_entry
*));
746 while ((p
= fgets(buf
, sizeof(buf
), f
))) {
749 char obuf
[MAXLINE
], genre
[MAXLINE
], desc
[MAXLINE
];
750 uint8_t quirks
[MAXLINE
];
751 char w
[MAXLINE
], sb
[MAXLINE
];
754 fp_entry asig
= {0}; //guarantee it's empty this sig
759 /* Remove leading and trailing blanks */
763 while (l
&& isspace(*(p
+ l
- 1)))
764 *(p
+ (l
--) - 1) = 0;
766 /* Skip empty lines and comments */
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
);
801 fatal("Empty OS genre in line %d.\n", ln
);
804 asig
.os
= strdup(gptr
);
805 asig
.desc
= strdup(desc
);
810 parse_sig_wsize(&asig
, w
);
812 parse_sig_options(&asig
, obuf
);
813 parse_sig_quirks(&asig
, quirks
);
814 uint32_t index
= SIGHASH(s
, asig
.optcnt
, asig
.quirks
, d
) % hashsize
;
818 sig
[index
] = alloc_sig(&asig
);
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
);
839 if (++sigcnt >= hashsize)
840 fatal("Maximum signature count exceeded.\n");
849 for (i
= 0; i
< sigcnt
; i
++) {
858 printf("Hash table layout: ");
859 for (i
= 0; i
< hashsize
; i
++) {
870 #endif /* DEBUG_HASH */
873 debug("[+] Signature collision check successful.\n");
877 debug("[!] WARNING: no signatures loaded from config file.\n");
883 /* run through the hash, free entries, then free hash */
884 void unload_sigs(fp_entry
**sigp
, int size
)
892 sigp
[i
] = NULL
; // clear
900 /* a dns cache of one? */
904 static inline char* grab_name(uint8_t* a
) {
906 static char rbuf
[MY_MAXDNS
+6] = "/";
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 "";
916 if (isalnum(*s
) || *s
== '-' || *s
== '.') *d
= *s
;
929 char* lookup_link(uint16_t mss
, char txt
) {
933 if (!mss
) return txt
? "unspecified" : 0;
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
;
944 sprintf(tmp
,"unknown-%d",mss
);
950 static char* lookup_tos(uint8_t t
) {
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;
965 void dump_packet(const uint8_t* pkt
,uint16_t plen
) {
967 uint8_t tbuf
[PKT_DLEN
+1];
970 for (i
=0;i
<plen
;i
++) {
971 uint8_t c
= *(pkt
++);
972 if (!(i
% PKT_DLEN
)) dlog(" [%02x] ",i
);
974 *(t
++) = isprint(c
) ? c
: '.';
975 if (!((i
+1) % PKT_DLEN
)) {
977 dlog(" | %s\n",(t
=tbuf
));
981 if (plen
% PKT_DLEN
) {
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];
994 uint8_t max
= dlen
> PKT_MAXPAY
? PKT_MAXPAY
: dlen
;
998 for (i
=0;i
<max
;i
++) {
999 if (isprint(*data
)) *(t
++) = *data
;
1000 else if (!*data
) *(t
++) = '?';
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
;
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
;
1029 *quirks
|= QUIRK_ACK
;
1031 *quirks
|= QUIRK_URG
;
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
)
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;
1050 // * let the phun begin...
1051 switch (*(opt_ptr
++)) {
1054 op
[ocnt
] = TCPOPT_EOL
;
1057 *quirks
|= QUIRK_PAST
;
1063 op
[ocnt
] = TCPOPT_NOP
;
1068 op
[ocnt
] = TCPOPT_SACKOK
;
1075 if (opt_ptr
+ 3 > end_ptr
) {
1077 *quirks
|= QUIRK_BROKEN
;
1080 op
[ocnt
] = TCPOPT_MAXSEG
;
1081 e
->mss
= GET16(opt_ptr
+ 1);
1088 if (opt_ptr
+ 2 > end_ptr
)
1090 op
[ocnt
] = TCPOPT_WSCALE
;
1091 e
->wsc
= *(uint8_t *) (opt_ptr
+ 1);
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
)
1101 op
[ocnt
] = TCPOPT_TIMESTAMP
;
1103 memcpy(&tstamp
, opt_ptr
+ 5, 4);
1105 *quirks
|= QUIRK_T2
;
1107 memcpy(&tstamp
, opt_ptr
+ 1, 4);
1108 tstamp
= ntohl(tstamp
);
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..
1121 if (opt_ptr
+ 1 > end_ptr
)
1124 op
[ocnt
] = *(opt_ptr
- 1);
1125 olen
= *(uint8_t *) (opt_ptr
) - 1;
1126 if (olen
> 32 || (olen
< 0))
1135 if (ocnt
>= MAXOPT
- 1)
1138 // * Whoops, we're past end_ptr
1140 if (opt_ptr
>= end_ptr
)
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
,
1161 /* uses the following values
1162 // uint16_t tot // e->size
1163 // uint8_t df, // e->
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)
1170 // uint8_t ocnt, // optcnt
1171 // uint8_t* op, // opt
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
1186 uint8_t orig_df
= e
->df
;
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;
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);
1204 /* Cheap and specific checks first... */
1205 // esize == 0 => open_mode
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... */
1220 if (e
->mss
^ p
->mss
) { p
= p
->next
; continue; }
1221 } else if (e
->mss
% p
->mss
) { p
= p
->next
; continue; }
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
) {
1230 if (e
->wsize
^ p
->wsize
) { p
= p
->next
; continue; }
1233 if (e
->wsize
% p
->wsize
) { p
= p
->next
; continue; }
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; }
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; }
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
;
1264 /* Naah... can't happen ;-) */
1266 if (p
->ttl
- e
->ttl
> MAXDIST
) {
1267 if (use_fuzzy
) fuzzy
= p
;
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;
1289 // copy in the os/desc pointers. These are not to be free()d!
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
);
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);
1324 olog(":%s:?] ",p
->os
);
1329 if (!no_extra
&& !p
->no_detail
) {
1330 if (!mode_oneline
) olog("\n ");
1332 u_ntop_dst(pi
, outbuf
);
1336 olog("-> %s:%d (link: %s)",outbuf
, PI_TCP_DP(pi
),
1337 lookup_link(e
->mss
,1));
1339 olog("-> %s:%d (distance %d, link: %s)",outbuf
, PI_TCP_DP(pi
),
1341 lookup_link(e
->mss
,1));
1343 if (p
->generic
) olog("[GENERIC] ");
1344 if (fuzzy_now
) olog("[FUZZY] ");
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(" -- ");
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);
1389 if (!e
->df
) { e
->df
= 1; goto re_lookup
; }
1391 if (use_fuzzy
&& fuzzy
) {
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;
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);
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 */
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 */
1434 vlog(2, "(dropped) "); break;
1436 /* RST, SEQ=m, ACK=n */
1438 vlog(2, "(dropped 2) "); break;
1440 /* RST, SEQ=0, ACK=0 */
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);
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));
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);
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
);
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)];
1506 bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)] =
1511 e->next = sig + sigcnt;
1515 fp_entry
*fp_tcp(packetinfo
*pi
, uint8_t ftype
)
1518 const uint8_t * end_ptr
;
1519 uint8_t *payload
= 0;
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
;
1530 opt_ptr
= (uint8_t *) pi
->ip6
+ IP6_HEADER_LEN
+ ntohs(pi
->ip6
->len
); //*
1531 if (end_ptr
> opt_ptr
)
1533 // If IP header ends past end_ptr
1534 if ((uint8_t *) (pi
->ip6
+ 1) > end_ptr
)
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
;
1552 opt_ptr
= (uint8_t *) pi
->ip4
+ ntohs(pi
->ip4
->ip_len
); // fixed from htons
1553 if (end_ptr
> opt_ptr
)
1555 if ((uint8_t *) (pi
->ip4
+ 1) > end_ptr
)
1557 ilen
= pi
->ip4
->ip_vhl
& 15;
1559 /* * B0rked packet */
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
;
1572 // default: there is no default
1574 fprintf(stderr
, "tcp_fp: something very unsafe happened!\n");
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
) {
1602 } else if (ftype
== CO_SYNACK
) {
1603 sig
=config
.sig_synack
;
1604 } else if (ftype
== CO_RST
) {
1606 } else if (ftype
== CO_FIN
) {
1608 } else if (ftype
== CO_ACK
) {
1613 fp_entry
*match
= NULL
;
1615 match
= find_match(sig
,
1616 config
.sig_hashsize
,
1618 pi
, // pass all packet characteristics
1620 end_ptr
- (uint8_t *) pi
->ip4
,
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)),
1633 mss_val, ntohs(tcph->t_win));
1637 // /* sp */ ntohs(tcph->sport),
1638 // /* dp */ ntohs(tcph->dport),
1641 // /* mss */ mss_val,
1642 // /* wsc */ wsc_val,
1643 // /* tst */ tstamp,
1644 // /* TOS */ iph->tos,
1646 // /* ECN */ tcph->flags & (TH_ECE|TH_CWR),
1647 // /* pkt */ (_u8*)iph,
1648 // /* len */ end_ptr - (_u8*)iph,
1657 void dump_sigs(fp_entry
*mysig
[], int max
)
1660 for (i
= 0; i
< max
; i
++){
1661 if (!mysig
[i
] || !mysig
[i
]->os
)
1663 print_sigs(mysig
[i
]);
1668 #ifdef SIG_STANDALONE
1670 int main(int argc
, char **argv
)
1673 fp_entry
**siga
[16] = {0};
1676 fprintf(stderr
, "Where are my sigs?\n");
1681 load_sigs(*argv
, &siga
[i
], HSIZE
);
1682 dump_sigs(siga
[i
], HSIZE
);
1683 unload_sigs(siga
[i
], HSIZE
);