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
));
160 } else if (af
== AF_INET6
) {
161 hash
= CXT_HASH6(ip_src
,ip_dst
);
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;
264 for (iter
= 0; iter
< BUCKET_SIZE
; iter
++) {
266 while (cxt
!= NULL
) {
270 if (cxt
->proto
== IP_PROTO_TCP
) {
271 /* * FIN from both sides */
272 if (cxt
->s_tcpFlags
& TF_FIN
&& cxt
->d_tcpFlags
& TF_FIN
273 && (check_time
- cxt
->last_pkt_time
) > 5) {
275 } /* * RST from either side */
276 else if ((cxt
->s_tcpFlags
& TF_RST
277 || cxt
->d_tcpFlags
& TF_RST
)
278 && (check_time
- cxt
->last_pkt_time
) > 5) {
281 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
286 else if (cxt
->proto
== IP_PROTO_UDP
287 && (check_time
- cxt
->last_pkt_time
) > 60) {
291 else if (cxt
->proto
== IP_PROTO_ICMP
292 || cxt
->proto
== IP6_PROTO_ICMP
) {
293 if ((check_time
- cxt
->last_pkt_time
) > 60) {
297 /* All Other protocols */
298 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
302 if (ended
== 1 || expired
== 1) {
303 /* remove from the hash */
305 cxt
->prev
->next
= cxt
->next
;
307 cxt
->next
->prev
= cxt
->prev
;
308 connection
*tmp
= cxt
;
310 if (config
.cflags
& CONFIG_CXWRITE
) {
312 log_connection(cxt
, stdout
, CX_EXPIRE
);
314 log_connection(cxt
, stdout
, CX_ENDED
);
321 del_connection(tmp
, &bucket
[iter
]);
332 void log_connection_all()
336 if(! (config
.cflags
& CONFIG_CXWRITE
))
338 for(i
= 0; i
< BUCKET_SIZE
; i
++) {
341 log_connection(cxt
, stdout
, CX_HUMAN
);
347 void del_connection(connection
* cxt
, connection
** bucket_ptr
)
349 connection
*prev
= cxt
->prev
; /* OLDER connections */
350 connection
*next
= cxt
->next
; /* NEWER connections */
358 } else if (next
== NULL
) {
368 * Free and set to NULL
374 void end_all_sessions()
379 for (cxkey
= 0; cxkey
< BUCKET_SIZE
; cxkey
++) {
381 while (cxt
!= NULL
) {
382 connection
*tmp
= cxt
;
384 if(config
.cflags
& CONFIG_CXWRITE
)
385 log_connection(cxt
, stdout
, CX_ENDED
);
388 del_connection(tmp
, &bucket
[cxkey
]);
390 bucket
[cxkey
] = NULL
;
396 /* vector comparisons to speed up cx tracking.
397 * meaning, compare source:port and dest:port at the same time.
399 * about vectors and potential improvements:
401 * all 64bit machines have at least SSE2 instructions
402 * *BUT* there is no guarantee we won't loose time on
403 * copying the vectors around.
404 * ... indeed, a quick objdump shows us that
405 * there is a shitton of mov instructions to align the addresses.
407 * Needs support to give improvements:
408 * the addresses should already be aligned as a 128-bit word
409 * in the connection tracking bucket.
411 * note, we can employ the same technique for ipv6 addresses, but
412 * one address at a time.
414 #ifdef VECTOR_CXTRACKER
415 // vector fill: srcprt,dstprt,srcip,dstip = 96 bytes. rest is 0
416 #define VEC_FILL(vec, _ipsrc,_ipdst,_portsrc,_portdst) do {\
417 vec.s[0] = (_portsrc); \
418 vec.s[1] = (_portdst); \
419 vec.w[1] = (_ipsrc); \
420 vec.w[2] = (_ipdst); \
424 inline void cx_track_simd_ipv4(packetinfo
*pi
)
426 connection
*cxt
= NULL
;
427 connection
*head
= NULL
;
430 // add to packetinfo ? dont through int32 around :)
431 hash
= make_hash(pi
);
438 pi
->ip_src
.__u6_addr
.__u6_addr32
[0],
439 pi
->ip_dst
.__u6_addr
.__u6_addr32
[0],
442 while (cxt
!= NULL
) {
444 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
445 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
449 // single-instruction compare -msse2
450 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
451 // same thing, really. c == v iff c ^ v == 0
452 //compare.v = compare.v ^ incoming.v;
454 // 64-bit compare reduce
455 if(!(compare
.i
[0] & compare
.i
[1])){
457 dlog("[*] Updating src connection: %lu\n",cxt
->cxid
);
458 cxt_update_src(cxt
,pi
);
462 // compare the other direction
464 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
465 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
469 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
470 if(!(compare
.i
[0] & compare
.i
[1])){
471 dlog("[*] Updating dst connection: %lu\n",cxt
->cxid
);
472 cxt_update_dst(cxt
,pi
);
478 cxt
= (connection
*) connection_alloc();
479 //cxt = (connection *) calloc(1, sizeof(connection));
484 dlog("[*] New connection: %lu\n",cxt
->cxid
);
489 printf("[*] Error in session tracking...\n");