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);
54 extern globalconfig config
;
57 #define SIG_HASHSIZE 1024
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
;
79 static uint8_t no_extra
,
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
)
94 bstring fp
= bformat("");
95 for (j
= 0; j
< ocnt
; j
++) {
101 bformata(fp
, "W%d", wsc
);
104 bformata(fp
, "M%d", mss
);
106 case TCPOPT_TIMESTAMP
:
118 bformata(fp
, "?%d", op
[j
]);
121 if(!config
.tcpopt_parsable
) // experimental format change!
132 bstring
gen_fp_tcpquirks(uint32_t quirks
)
134 bstring fp
= bformat("");
138 if (quirks
& QUIRK_RSTACK
)
140 if (quirks
& QUIRK_SEQEQ
)
142 if (quirks
& QUIRK_SEQ0
)
144 if (quirks
& QUIRK_PAST
)
146 if (quirks
& QUIRK_ZEROID
)
148 if (quirks
& QUIRK_IPOPT
)
150 if (quirks
& QUIRK_URG
)
152 if (quirks
& QUIRK_X2
)
154 if (quirks
& QUIRK_ACK
)
156 if (quirks
& QUIRK_T2
)
158 if (quirks
& QUIRK_FLAGS
)
160 if (quirks
& QUIRK_DATA
)
164 if (quirks
& QUIRK_FINACK
)
166 if (quirks
& QUIRK_FLOWL
)
169 if (quirks
& QUIRK_BROKEN
)
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
)
195 uint16_t mss
, wss
, tot
;
197 bstring fp
, fpopt
, fpquirks
;
203 ttl
= e
->ttl
; //normalize_ttl(e->ttl);
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)");
218 bformata(fp
, "%d", wss
);
221 if ( tf
== TF_ACK
|| tf
== TF_RST
) {
222 bformata(fp
, ":%d:%d:*:",ttl
, e
->df
);
224 if (e
->size
< PACKET_BIG
)
225 bformata(fp
, ":%d:%d:%d:", ttl
, e
->df
, e
->size
);
227 bformata(fp
, ":%d:%d:*(%d):", ttl
, e
->df
, e
->size
);
231 fpopt
= gen_fp_tcpopt(( tf
== TF_ACK
? TCPOPT_LIMIT
: e
->optcnt
), e
->opt
, mss
, wss
, e
->wsc
, tstamp
);
238 fpquirks
= gen_fp_tcpquirks(e
->quirks
);
239 bconcat(fp
, fpquirks
);
242 //if (tstamp) printf("(* uptime: %d hrs)\n",tstamp/360000);
243 //update_asset_os(pi, tf, fp, tstamp?tstamp:0);
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
, '-');
257 printf("],%s:%s\n", e
->os
, e
->desc
);
259 void print_sigs(fp_entry
* e
)
267 static void collide(uint32_t id)
272 if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30) {
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)) {
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)
293 if (sig[id].df ^ sig[i].df)
295 if (sig[id].zero_stamp ^ sig[i].zero_stamp)
298 // * Zero means >= PACKET_BIG
300 if (sig[id].size ^ sig[i].size)
302 } else if (sig[i].size < PACKET_BIG)
305 if (sig[id].optcnt ^ sig[i].optcnt)
307 if (sig[id].quirks ^ sig[i].quirks)
310 switch (sig[id].wsize_mod) {
312 case 0: // Current: 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)
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)
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)
342 case MOD_MTU: // Current: const, prev: mod MTU
345 || sig[i].wsize * ((sig[i].mss ? sig[i].mss : 1460) +
355 case 1: // Current signature is modulo something
357 // A problem only if this modulo is a multiple of the
360 if (sig[i].wsize_mod != MOD_CONST)
362 if (sig[id].wsize % sig[i].wsize)
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
375 if (sig[i].wsize_mod != MOD_CONST || sig[i].wsize >= 8) {
376 if (!sig[id].mss_mod) {
378 (sig[id].mss ? sig[id].mss : 1460) * sig[id].wsize;
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) {
391 ((sig[id].mss ? sig[id].mss : 1460) +
403 switch (sig[id].wsc_mod) {
405 case 0: // Current: const
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)
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)
429 case MOD_CONST: // Current signature is modulo something
431 // A problem only if this modulo is a multiple of the
436 if (sig[id].wsc % sig[i].wsc)
444 switch (sig[id].mss_mod) {
446 case 0: // Current: const
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)
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)
470 case MOD_CONST: // Current signature is modulo something
472 // A problem only if this modulo is a multiple of the
476 if ((sig[id].mss ? sig[id].mss : 1460) %
477 (sig[i].mss ? sig[i].mss : 1460))
484 // Now check option sequence
485 for (j = 0; j < sig[id].optcnt; j++)
486 if (sig[id].opt[j] ^ sig[i].opt[j])
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);
500 /* recursively free signatures */
501 static void free_sigs(fp_entry
*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
));
517 /* parse the wss field of the signature line */
518 static int parse_sig_wsize(fp_entry
*sig
, char* w
)
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",
537 sig
->wsize_mod
= MOD_CONST
;
539 sig
->wsize
= atoi(w
);
544 /* parse the option field of the signature line */
545 static int parse_sig_options(fp_entry
*sig
, char* p
)
553 uint8_t optcnt
= sig
->optcnt
;
554 switch (tolower(*p
)) {
557 sig
->opt
[optcnt
] = TCPOPT_NOP
;
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);
567 sig
->opt
[optcnt
] = TCPOPT_SACKOK
;
571 sig
->opt
[optcnt
] = TCPOPT_TIMESTAMP
;
572 if (*(p
+ 1) != '0') {
574 if (isdigit(*(p
+ 1)))
575 fatal("Bogus Tstamp specification in line %d.\n",
581 sig
->opt
[optcnt
] = TCPOPT_WSCALE
;
584 sig
->wsc_mod
= MOD_CONST
;
585 } else if (p
[1] == '%') {
586 if (!(sig
->wsc
= atoi(p
+ 2)))
588 ("Null modulo for wscale in config line %d.\n",
590 sig
->wsc_mod
= MOD_CONST
;
591 } else if (!isdigit(*(p
+ 1)))
592 fatal("Incorrect W value in line %d.\n", sig
->line
);
594 sig
->wsc
= atoi(p
+ 1);
598 sig
->opt
[optcnt
] = TCPOPT_MAXSEG
;
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",
606 sig
->mss_mod
= MOD_CONST
;
607 } else if (!isdigit(*(p
+ 1)))
608 fatal("Incorrect M value in line %d.\n", sig
->line
);
610 sig
->mss
= atoi(p
+ 1);
617 if (!isdigit(*(p
+ 1)))
618 fatal("Bogus ?nn value in line %d.\n", sig
->line
);
620 sig
->opt
[optcnt
] = atoi(p
+ 1);
624 fatal("Unknown TCP option '%c' in config line %d.\n", *p
,
628 if (++sig
->optcnt
>= MAXOPT
)
630 ("Too many TCP options specified in config line %d.\n",
638 } while (*p
&& !isalpha(*p
) && *p
!= '?');
643 /* parse the quirks field of the signature line */
644 static int parse_sig_quirks(fp_entry
*sig
, uint8_t *p
)
647 switch (toupper(*(p
++))) {
650 ("Quirk 'E' (line %d) is obsolete. Remove it, append E to the "
651 "options.\n", sig
->line
);
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
;
662 sig
->quirks
|= QUIRK_DATA
;
666 sig
->quirks
|= QUIRK_SEQEQ
;
669 sig
->quirks
|= QUIRK_SEQ0
;
672 sig
->quirks
|= QUIRK_PAST
;
675 sig
->quirks
|= QUIRK_ZEROID
;
678 sig
->quirks
|= QUIRK_IPOPT
;
681 sig
->quirks
|= QUIRK_URG
;
684 sig
->quirks
|= QUIRK_X2
;
687 sig
->quirks
|= QUIRK_ACK
;
690 sig
->quirks
|= QUIRK_T2
;
693 sig
->quirks
|= QUIRK_FLAGS
;
696 sig
->quirks
|= QUIRK_FINACK
;
699 sig
->quirks
|= QUIRK_FLOWL
;
702 sig
->quirks
|= QUIRK_BROKEN
;
707 fatal("Bad quirk '%c' in line %d.\n", *(p
- 1), sig
->line
);
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.
728 int load_sigs(const char *file
, fp_entry
**sigp
[], int hashsize
)
730 fp_entry
**sig
; // output
732 //debug("opening %s\n", file);
733 FILE *f
= fopen(file
, "r");
737 perror("failed to open file");
742 perror("need a pointer to fill");
746 hashsize
= SIG_HASHSIZE
;
748 *sigp
= calloc(hashsize
, sizeof(fp_entry
*));
752 while ((p
= fgets(buf
, sizeof(buf
), f
))) {
755 char obuf
[MAXLINE
], genre
[MAXLINE
], desc
[MAXLINE
];
756 uint8_t quirks
[MAXLINE
];
757 char w
[MAXLINE
], sb
[MAXLINE
];
760 fp_entry asig
= {0}; //guarantee it's empty this sig
765 /* Remove leading and trailing blanks */
769 while (l
&& isspace(*(p
+ l
- 1)))
770 *(p
+ (l
--) - 1) = 0;
772 /* Skip empty lines and comments */
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
);
807 fatal("Empty OS genre in line %d.\n", ln
);
810 asig
.os
= strdup(gptr
);
811 asig
.desc
= strdup(desc
);
816 parse_sig_wsize(&asig
, w
);
818 parse_sig_options(&asig
, obuf
);
819 parse_sig_quirks(&asig
, quirks
);
820 uint32_t index
= SIGHASH(s
, asig
.optcnt
, asig
.quirks
, d
) % hashsize
;
824 sig
[index
] = alloc_sig(&asig
);
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
);
845 if (++sigcnt >= hashsize)
846 fatal("Maximum signature count exceeded.\n");
855 for (i
= 0; i
< sigcnt
; i
++) {
864 printf("Hash table layout: ");
865 for (i
= 0; i
< hashsize
; i
++) {
876 #endif /* DEBUG_HASH */
879 debug("[+] Signature collision check successful.\n");
883 debug("[!] WARNING: no signatures loaded from config file.\n");
889 /* run through the hash, free entries, then free hash */
890 void unload_sigs(fp_entry
**sigp
, int size
)
898 sigp
[i
] = NULL
; // clear
906 /* a dns cache of one? */
910 static inline char* grab_name(uint8_t* a
) {
912 static char rbuf
[MY_MAXDNS
+6] = "/";
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 "";
922 if (isalnum(*s
) || *s
== '-' || *s
== '.') *d
= *s
;
935 uint8_t* lookup_link(uint16_t mss
, uint8_t txt
) {
939 if (!mss
) return txt
? "unspecified" : 0;
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
;
950 sprintf(tmp
,"unknown-%d",mss
);
956 static char* lookup_tos(uint8_t t
) {
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;
971 void dump_packet(const uint8_t* pkt
,uint16_t plen
) {
973 uint8_t tbuf
[PKT_DLEN
+1];
976 for (i
=0;i
<plen
;i
++) {
977 uint8_t c
= *(pkt
++);
978 if (!(i
% PKT_DLEN
)) dlog(" [%02x] ",i
);
980 *(t
++) = isprint(c
) ? c
: '.';
981 if (!((i
+1) % PKT_DLEN
)) {
983 dlog(" | %s\n",(t
=tbuf
));
987 if (plen
% PKT_DLEN
) {
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];
1000 uint8_t max
= dlen
> PKT_MAXPAY
? PKT_MAXPAY
: dlen
;
1004 for (i
=0;i
<max
;i
++) {
1005 if (isprint(*data
)) *(t
++) = *data
;
1006 else if (!*data
) *(t
++) = '?';
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
;
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
;
1035 *quirks
|= QUIRK_ACK
;
1037 *quirks
|= QUIRK_URG
;
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
)
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;
1056 // * let the phun begin...
1057 switch (*(opt_ptr
++)) {
1060 op
[ocnt
] = TCPOPT_EOL
;
1063 *quirks
|= QUIRK_PAST
;
1069 op
[ocnt
] = TCPOPT_NOP
;
1074 op
[ocnt
] = TCPOPT_SACKOK
;
1081 if (opt_ptr
+ 3 > end_ptr
) {
1083 *quirks
|= QUIRK_BROKEN
;
1086 op
[ocnt
] = TCPOPT_MAXSEG
;
1087 e
->mss
= GET16(opt_ptr
+ 1);
1094 if (opt_ptr
+ 2 > end_ptr
)
1096 op
[ocnt
] = TCPOPT_WSCALE
;
1097 e
->wsc
= *(uint8_t *) (opt_ptr
+ 1);
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
)
1107 op
[ocnt
] = TCPOPT_TIMESTAMP
;
1109 memcpy(&tstamp
, opt_ptr
+ 5, 4);
1111 *quirks
|= QUIRK_T2
;
1113 memcpy(&tstamp
, opt_ptr
+ 1, 4);
1114 tstamp
= ntohl(tstamp
);
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..
1127 if (opt_ptr
+ 1 > end_ptr
)
1130 op
[ocnt
] = *(opt_ptr
- 1);
1131 olen
= *(uint8_t *) (opt_ptr
) - 1;
1132 if (olen
> 32 || (olen
< 0))
1141 if (ocnt
>= MAXOPT
- 1)
1144 // * Whoops, we're past end_ptr
1146 if (opt_ptr
>= end_ptr
)
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
,
1167 /* uses the following values
1168 // uint16_t tot // e->size
1169 // uint8_t df, // e->
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)
1176 // uint8_t ocnt, // optcnt
1177 // uint8_t* op, // opt
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
1192 uint8_t orig_df
= e
->df
;
1195 fp_entry
* fuzzy
= 0;
1196 uint8_t fuzzy_now
= 0;
1197 char outbuf
[INET6_ADDRSTRLEN
+1];
1199 uint8_t *payhead
= 0x0;
1201 payhead
= (uint8_t*) pi
->ip4
;
1203 payhead
= (uint8_t*) pi
->ip6
;
1206 //if ( sig == config.sig_ack ) e->optcnt = 3;
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);
1217 /* Cheap and specific checks first... */
1218 // esize == 0 => open_mode
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... */
1233 if (e
->mss
^ p
->mss
) { p
= p
->next
; continue; }
1234 } else if (e
->mss
% p
->mss
) { p
= p
->next
; continue; }
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
) {
1243 if (e
->wsize
^ p
->wsize
) { p
= p
->next
; continue; }
1246 if (e
->wsize
% p
->wsize
) { p
= p
->next
; continue; }
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; }
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; }
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
;
1277 /* Naah... can't happen ;-) */
1279 if (p
->ttl
- e
->ttl
> MAXDIST
) {
1280 if (use_fuzzy
) fuzzy
= p
;
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;
1302 // copy in the os/desc pointers. These are not to be free()d!
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
);
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);
1337 olog(":%s:?] ",p
->os
);
1342 if (!no_extra
&& !p
->no_detail
) {
1343 if (!mode_oneline
) olog("\n ");
1345 u_ntop_dst(pi
, outbuf
);
1349 olog("-> %s:%d (link: %s)",outbuf
, PI_TCP_DP(pi
),
1350 lookup_link(e
->mss
,1));
1352 olog("-> %s:%d (distance %d, link: %s)",outbuf
, PI_TCP_DP(pi
),
1354 lookup_link(e
->mss
,1));
1356 if (p
->generic
) olog("[GENERIC] ");
1357 if (fuzzy_now
) olog("[FUZZY] ");
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(" -- ");
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);
1404 if (!e
->df
) { e
->df
= 1; goto re_lookup
; }
1406 if (use_fuzzy
&& fuzzy
) {
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;
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);
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 */
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 */
1451 vlog(2, "(dropped) "); break;
1453 /* RST, SEQ=m, ACK=n */
1455 vlog(2, "(dropped 2) "); break;
1457 /* RST, SEQ=0, ACK=0 */
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);
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));
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);
1497 if (pay
&& payload_dump
) dump_payload(pay
,plen
- (pay
- payhead
));
1499 if (full_dump
) dump_packet(payhead
,plen
);
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)];
1525 bh[SIGHASH(s, sig[sigcnt].optcnt, sig[sigcnt].quirks, d)] =
1530 e->next = sig + sigcnt;
1534 fp_entry
*fp_tcp(packetinfo
*pi
, uint8_t ftype
)
1537 const uint8_t * end_ptr
;
1538 uint8_t *payload
= 0;
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
;
1549 opt_ptr
= (uint8_t *) pi
->ip6
+ IP6_HEADER_LEN
+ ntohs(pi
->ip6
->len
); //*
1550 if (end_ptr
> opt_ptr
)
1552 // If IP header ends past end_ptr
1553 if ((uint8_t *) (pi
->ip6
+ 1) > end_ptr
)
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
;
1571 opt_ptr
= (uint8_t *) pi
->ip4
+ ntohs(pi
->ip4
->ip_len
);
1572 if (end_ptr
> opt_ptr
)
1574 if ((uint8_t *) (pi
->ip4
+ 1) > end_ptr
)
1576 ilen
= pi
->ip4
->ip_vhl
& 15;
1578 /* * B0rked packet */
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
;
1591 // default: there is no default
1593 fprintf(stderr
, "tcp_fp: something very unsafe happened!\n");
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
) {
1621 } else if (ftype
== CO_SYNACK
) {
1622 sig
=config
.sig_synack
;
1623 } else if (ftype
== CO_RST
) {
1625 } else if (ftype
== CO_FIN
) {
1627 } else if (ftype
== CO_ACK
) {
1632 fp_entry
*match
= NULL
;
1634 match
= find_match(sig
,
1635 config
.sig_hashsize
,
1637 pi
, // pass all packet characteristics
1639 end_ptr
- (uint8_t *) pi
->ip4
,
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)),
1652 mss_val, ntohs(tcph->t_win));
1656 // /* sp */ ntohs(tcph->sport),
1657 // /* dp */ ntohs(tcph->dport),
1660 // /* mss */ mss_val,
1661 // /* wsc */ wsc_val,
1662 // /* tst */ tstamp,
1663 // /* TOS */ iph->tos,
1665 // /* ECN */ tcph->flags & (TH_ECE|TH_CWR),
1666 // /* pkt */ (_u8*)iph,
1667 // /* len */ end_ptr - (_u8*)iph,
1676 void dump_sigs(fp_entry
*mysig
[], int max
)
1679 for (i
= 0; i
< max
; i
++){
1680 if (!mysig
[i
] || !mysig
[i
]->os
)
1682 print_sigs(mysig
[i
]);
1687 #ifdef SIG_STANDALONE
1689 int main(int argc
, char **argv
)
1692 fp_entry
**siga
[16] = {0};
1695 fprintf(stderr
, "Where are my sigs?\n");
1700 load_sigs(*argv
, &siga
[i
], HSIZE
);
1701 dump_sigs(siga
[i
], HSIZE
);
1702 unload_sigs(siga
[i
], HSIZE
);