7 #include "output-plugins/log.h"
9 extern globalconfig config
;
12 connection
*bucket
[BUCKET_SIZE
];
19 /* freshly smelling connection :d */
20 connection
*cxt_new(packetinfo
*pi
)
26 cxt
= (connection
*) calloc(1, sizeof(connection
));
28 cxt
->cxid
= cxtrackerid
;
31 if(pi
->tcph
) cxt
->s_tcpFlags
|= pi
->tcph
->t_flags
;
32 //cxt->s_tcpFlags |= (pi->tcph ? pi->tcph->t_flags : 0x00);//why??
33 //cxt->d_tcpFlags = 0x00;
34 cxt
->s_total_bytes
= pi
->packet_bytes
;
35 cxt
->s_total_pkts
= 1;
36 cxt
->start_time
= pi
->pheader
->ts
.tv_sec
;
37 cxt
->last_pkt_time
= pi
->pheader
->ts
.tv_sec
;
39 if(pi
-> af
== AF_INET6
){
40 cxt
->s_ip
= PI_IP6SRC(pi
);
41 cxt
->d_ip
= PI_IP6DST(pi
);
44 // the way we do ip4/6 is DIRTY
45 ips
.s6_addr32
[0] = pi
->ip4
->ip_src
;
46 ipd
.s6_addr32
[0] = pi
->ip4
->ip_dst
;
51 cxt
->s_port
= pi
->s_port
;
52 cxt
->d_port
= pi
->d_port
;
53 cxt
->proto
= pi
->proto
;
63 int connection_tracking(packetinfo
*pi
)
65 static char ip_addr_s
[INET6_ADDRSTRLEN
];
66 static char ip_addr_d
[INET6_ADDRSTRLEN
];
70 if(pi
->af
== AF_INET6
) {
71 u_ntop(pi
->ip6
->ip_src
, pi
->af
, ip_addr_s
);
72 u_ntop(pi
->ip6
->ip_dst
, pi
->af
, ip_addr_d
);
74 ipa
= pi
->ip4
->ip_src
;
75 inet_ntop(pi
->af
, &ipa
, ip_addr_s
, INET6_ADDRSTRLEN
);
76 ipa
= pi
->ip4
->ip_dst
;
77 inet_ntop(pi
->af
, &ipa
, ip_addr_d
, INET6_ADDRSTRLEN
);
79 if(config
.cflags
& CONFIG_CONNECT
)
80 printf("conn[%4lu] %s:%u -> %s:%u [%s]\n", pi
->cxt
->cxid
,
81 ip_addr_s
, ntohs(pi
->s_port
),
82 ip_addr_d
, ntohs(pi
->d_port
),
83 pi
->sc
?pi
->sc
==SC_SERVER
? "server":"client":"NONE");
87 int cxt_update_client(connection
*cxt
, packetinfo
*pi
)
89 cxt
->last_pkt_time
= pi
->pheader
->ts
.tv_sec
;
91 if(pi
->tcph
) cxt
->s_tcpFlags
|= pi
->tcph
->t_flags
;
92 cxt
->s_total_bytes
+= pi
->packet_bytes
;
93 cxt
->s_total_pkts
+= 1;
98 cxt
->c_asset
= pi
->asset
; // connection client asset
99 if (cxt
->s_total_bytes
> MAX_BYTE_CHECK
100 || cxt
->s_total_pkts
> MAX_PKT_CHECK
) {
101 return 0; // Dont Check!
106 int cxt_update_server(connection
*cxt
, packetinfo
*pi
)
108 cxt
->last_pkt_time
= pi
->pheader
->ts
.tv_sec
;
110 if(pi
->tcph
) cxt
->d_tcpFlags
|= pi
->tcph
->t_flags
;
111 cxt
->d_total_bytes
+= pi
->packet_bytes
;
112 cxt
->d_total_pkts
+= 1;
117 cxt
->s_asset
= pi
->asset
; // server asset
118 if (cxt
->d_total_bytes
> MAX_BYTE_CHECK
119 || cxt
->d_total_pkts
> MAX_PKT_CHECK
) {
120 return 0; // Dont check!
126 /* return value: client or server?
127 *** USED TO BE: 0 = dont check, 1 = client, 2 = server
128 * now returns 0, SC_CLIENT(=1), SC_SERVER(=2)
131 int cx_track(packetinfo
*pi
) {
132 struct in6_addr
*ip_src
;
133 struct in6_addr
*ip_dst
;
136 uint16_t src_port
= pi
->s_port
;
137 uint16_t dst_port
= pi
->d_port
;
139 connection
*cxt
= NULL
;
140 connection
*head
= NULL
;
145 ip_src
= &PI_IP6SRC(pi
);
146 ip_dst
= &PI_IP6DST(pi
);
149 // the way we do ip4/6 is DIRTY
151 ips
.s6_addr32
[0] = pi
->ip4
->ip_src
;
152 ipd
.s6_addr32
[0] = pi
->ip4
->ip_dst
;
157 // find the right connection bucket
159 hash
= CXT_HASH4(IP4ADDR(ip_src
),IP4ADDR(ip_dst
),src_port
,dst_port
,pi
->proto
);
160 } else if (af
== AF_INET6
) {
161 hash
= CXT_HASH6(ip_src
,ip_dst
,src_port
,dst_port
,pi
->proto
);
166 // search through the bucket
167 while (cxt
!= NULL
) {
168 // Two-way compare of given connection against connection table
170 if (CMP_CXT4(cxt
,IP4ADDR(ip_src
),src_port
,IP4ADDR(ip_dst
),dst_port
)){
171 // Client sends first packet (TCP/SYN - UDP?) hence this is a client
172 return cxt_update_client(cxt
, pi
);
173 } else if (CMP_CXT4(cxt
,IP4ADDR(ip_dst
),dst_port
,IP4ADDR(ip_src
),src_port
)) {
174 // This is a server (Maybe not when we start up but in the long run)
175 return cxt_update_server(cxt
, pi
);
177 } else if (af
== AF_INET6
) {
178 if (CMP_CXT6(cxt
,ip_src
,src_port
,ip_dst
,dst_port
)){
179 return cxt_update_client(cxt
, pi
);
180 } else if (CMP_CXT6(cxt
,ip_dst
,dst_port
,ip_src
,src_port
)){
181 return cxt_update_server(cxt
, pi
);
186 // bucket turned upside down didn't yeild anything. new connection
188 if(config
.cflags
& CONFIG_CXWRITE
)
189 log_connection(cxt
, stdout
, CX_NEW
);
191 /* * New connections are pushed on to the head of bucket[s_hash] */
194 // are we doubly linked?
200 /* * Return value should be 1, telling to do client service fingerprinting */
204 void reverse_pi_cxt(packetinfo
*pi
)
209 struct in6_addr tmp_ip
;
215 /* First we chang the cxt */
217 tmpFlags
= cxt
->s_tcpFlags
;
218 tmp_pkts
= cxt
->s_total_pkts
;
219 tmp_bytes
= cxt
->s_total_bytes
;
221 tmp_port
= cxt
->s_port
;
224 cxt
->s_tcpFlags
= cxt
->d_tcpFlags
;
225 cxt
->s_total_pkts
= cxt
->d_total_pkts
;
226 cxt
->s_total_bytes
= cxt
->d_total_bytes
;
227 cxt
->s_ip
= cxt
->d_ip
;
228 cxt
->s_port
= cxt
->d_port
;
231 cxt
->d_tcpFlags
= tmpFlags
;
232 cxt
->d_total_pkts
= tmp_pkts
;
233 cxt
->d_total_bytes
= tmp_bytes
;
235 cxt
->d_port
= tmp_port
;
237 /* Not taking any chances :P */
238 cxt
->c_asset
= cxt
->s_asset
= NULL
;
241 /* Then we change pi */
242 if (pi
->sc
== SC_CLIENT
)
249 This sub marks sessions as ENDED on different criterias:
251 XXX: May be the fugliest code in PRADS :-(
259 check_time
= time(NULL
);
260 int ended
, expired
= 0;
262 FILE *cxtFile
= NULL
;
264 if (config
.cxtlogdir
[0] != '\0') {
265 if (config
.dev
== 0x00) {
266 sprintf(config
.cxtfname
, "%sstats.pcap.%ld", config
.cxtlogdir
, check_time
); // True?
268 sprintf(config
.cxtfname
, "%sstats.%s.%ld", config
.cxtlogdir
, config
.dev
, check_time
);
273 for (iter
= 0; iter
< BUCKET_SIZE
; iter
++) {
275 while (cxt
!= NULL
) {
279 if (cxt
->proto
== IP_PROTO_TCP
) {
280 /* * FIN from both sides */
281 if (cxt
->s_tcpFlags
& TF_FIN
&& cxt
->d_tcpFlags
& TF_FIN
282 && (check_time
- cxt
->last_pkt_time
) > 5) {
284 } /* * RST from either side */
285 else if ((cxt
->s_tcpFlags
& TF_RST
286 || cxt
->d_tcpFlags
& TF_RST
)
287 && (check_time
- cxt
->last_pkt_time
) > 5) {
290 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
295 else if (cxt
->proto
== IP_PROTO_UDP
296 && (check_time
- cxt
->last_pkt_time
) > 60) {
300 else if (cxt
->proto
== IP_PROTO_ICMP
301 || cxt
->proto
== IP6_PROTO_ICMP
) {
302 if ((check_time
- cxt
->last_pkt_time
) > 60) {
306 /* All Other protocols */
307 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
311 if (ended
== 1 || expired
== 1) {
312 /* remove from the hash */
314 cxt
->prev
->next
= cxt
->next
;
316 cxt
->next
->prev
= cxt
->prev
;
317 connection
*tmp
= cxt
;
319 if (config
.cxtfname
[0] != '\0' ) {
320 if (cxtFile
== NULL
) {
321 cxtFile
= fopen(config
.cxtfname
, "w");
322 dlog("Opened file: %s\n",config
.cxtfname
);
324 if (cxtFile
== NULL
) {
325 dlog("[*] ERROR: Cant open file %s\n",config
.cxtfname
);
327 log_connection(cxt
, cxtFile
, CX_NONE
);
330 if (config
.cflags
& CONFIG_CXWRITE
) {
332 log_connection(cxt
, stdout
, CX_EXPIRE
);
334 log_connection(cxt
, stdout
, CX_ENDED
);
341 del_connection(tmp
, &bucket
[iter
]);
350 if (cxtFile
!= NULL
) {
355 void log_connection_all()
359 if(! (config
.cflags
& CONFIG_CXWRITE
))
361 for(i
= 0; i
< BUCKET_SIZE
; i
++) {
364 log_connection(cxt
, stdout
, CX_HUMAN
);
370 void del_connection(connection
* cxt
, connection
** bucket_ptr
)
372 connection
*prev
= cxt
->prev
; /* OLDER connections */
373 connection
*next
= cxt
->next
; /* NEWER connections */
381 } else if (next
== NULL
) {
391 * Free and set to NULL
397 void end_all_sessions()
401 FILE *cxtFile
= NULL
;
403 if (config
.cxtlogdir
[0] != '\0') {
404 if (config
.dev
== 0x00) {
405 sprintf(config
.cxtfname
, "%sstats.pcap.%ld", config
.cxtlogdir
, time(NULL
)); // True?
407 sprintf(config
.cxtfname
, "%sstats.%s.%ld", config
.cxtlogdir
, config
.dev
, time(NULL
));
411 for (cxkey
= 0; cxkey
< BUCKET_SIZE
; cxkey
++) {
413 while (cxt
!= NULL
) {
414 connection
*tmp
= cxt
;
416 if (config
.cxtfname
[0] != '\0' ) {
417 if (cxtFile
== NULL
) {
418 cxtFile
= fopen(config
.cxtfname
, "w");
419 dlog("Opened file: %s\n",config
.cxtfname
);
421 if (cxtFile
== NULL
) {
422 dlog("[*] ERROR: Cant open file %s\n",config
.cxtfname
);
424 log_connection(cxt
, cxtFile
, CX_NONE
);
428 if(config
.cflags
& CONFIG_CXWRITE
)
429 log_connection(cxt
, stdout
, CX_ENDED
);
432 del_connection(tmp
, &bucket
[cxkey
]);
434 bucket
[cxkey
] = NULL
;
438 if (cxtFile
!= NULL
) {
443 /* vector comparisons to speed up cx tracking.
444 * meaning, compare source:port and dest:port at the same time.
446 * about vectors and potential improvements:
448 * all 64bit machines have at least SSE2 instructions
449 * *BUT* there is no guarantee we won't loose time on
450 * copying the vectors around.
451 * ... indeed, a quick objdump shows us that
452 * there is a shitton of mov instructions to align the addresses.
454 * Needs support to give improvements:
455 * the addresses should already be aligned as a 128-bit word
456 * in the connection tracking bucket.
458 * note, we can employ the same technique for ipv6 addresses, but
459 * one address at a time.
461 #ifdef VECTOR_CXTRACKER
462 // vector fill: srcprt,dstprt,srcip,dstip = 96 bytes. rest is 0
463 #define VEC_FILL(vec, _ipsrc,_ipdst,_portsrc,_portdst) do {\
464 vec.s[0] = (_portsrc); \
465 vec.s[1] = (_portdst); \
466 vec.w[1] = (_ipsrc); \
467 vec.w[2] = (_ipdst); \
471 inline void cx_track_simd_ipv4(packetinfo
*pi
)
473 connection
*cxt
= NULL
;
474 connection
*head
= NULL
;
477 // add to packetinfo ? dont through int32 around :)
478 hash
= make_hash(pi
);
485 pi
->ip_src
.__u6_addr
.__u6_addr32
[0],
486 pi
->ip_dst
.__u6_addr
.__u6_addr32
[0],
489 while (cxt
!= NULL
) {
491 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
492 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
496 // single-instruction compare -msse2
497 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
498 // same thing, really. c == v iff c ^ v == 0
499 //compare.v = compare.v ^ incoming.v;
501 // 64-bit compare reduce
502 if(!(compare
.i
[0] & compare
.i
[1])){
504 dlog("[*] Updating src connection: %lu\n",cxt
->cxid
);
505 cxt_update_src(cxt
,pi
);
509 // compare the other direction
511 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
512 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
516 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
517 if(!(compare
.i
[0] & compare
.i
[1])){
518 dlog("[*] Updating dst connection: %lu\n",cxt
->cxid
);
519 cxt_update_dst(cxt
,pi
);
525 cxt
= (connection
*) connection_alloc();
526 //cxt = (connection *) calloc(1, sizeof(connection));
531 dlog("[*] New connection: %lu\n",cxt
->cxid
);
536 printf("[*] Error in session tracking...\n");