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
);
43 ips
.s6_addr32
[0] = pi
->ip4
->ip_src
;
44 ipd
.s6_addr32
[0] = pi
->ip4
->ip_dst
;
49 cxt
->s_port
= pi
->s_port
;
50 cxt
->d_port
= pi
->d_port
;
51 cxt
->proto
= pi
->proto
;
52 cxt
->hw_proto
= ntohs(pi
->eth_type
);
62 int connection_tracking(packetinfo
*pi
)
64 static char ip_addr_s
[INET6_ADDRSTRLEN
];
65 static char ip_addr_d
[INET6_ADDRSTRLEN
];
68 if(config
.cflags
& CONFIG_CONNECT
){
69 log_connection(pi
->cxt
, CX_EXCESSIVE
);
74 int cxt_update_client(connection
*cxt
, packetinfo
*pi
)
76 cxt
->last_pkt_time
= pi
->pheader
->ts
.tv_sec
;
78 if(pi
->tcph
) cxt
->s_tcpFlags
|= pi
->tcph
->t_flags
;
79 cxt
->s_total_bytes
+= pi
->packet_bytes
;
80 cxt
->s_total_pkts
+= 1;
85 cxt
->c_asset
= pi
->asset
; // connection client asset
86 if (cxt
->s_total_bytes
> MAX_BYTE_CHECK
87 || cxt
->s_total_pkts
> MAX_PKT_CHECK
) {
88 return 0; // Dont Check!
93 int cxt_update_server(connection
*cxt
, packetinfo
*pi
)
95 cxt
->last_pkt_time
= pi
->pheader
->ts
.tv_sec
;
97 if(pi
->tcph
) cxt
->d_tcpFlags
|= pi
->tcph
->t_flags
;
98 cxt
->d_total_bytes
+= pi
->packet_bytes
;
99 cxt
->d_total_pkts
+= 1;
104 cxt
->s_asset
= pi
->asset
; // server asset
105 if (cxt
->d_total_bytes
> MAX_BYTE_CHECK
106 || cxt
->d_total_pkts
> MAX_PKT_CHECK
) {
107 return 0; // Dont check!
113 /* return value: client or server?
114 *** USED TO BE: 0 = dont check, 1 = client, 2 = server
115 * now returns 0, SC_CLIENT(=1), SC_SERVER(=2)
118 int cx_track(packetinfo
*pi
) {
119 struct in6_addr
*ip_src
;
120 struct in6_addr
*ip_dst
;
123 uint16_t src_port
= pi
->s_port
;
124 uint16_t dst_port
= pi
->d_port
;
126 connection
*cxt
= NULL
;
127 connection
*head
= NULL
;
132 ip_src
= &PI_IP6SRC(pi
);
133 ip_dst
= &PI_IP6DST(pi
);
136 // the way we do ip4/6 is DIRTY
137 ips
.s6_addr32
[0] = pi
->ip4
->ip_src
;
138 ipd
.s6_addr32
[0] = pi
->ip4
->ip_dst
;
143 // find the right connection bucket
145 hash
= CXT_HASH4(IP4ADDR(ip_src
),IP4ADDR(ip_dst
),src_port
,dst_port
,pi
->proto
);
146 } else if (af
== AF_INET6
) {
147 hash
= CXT_HASH6(ip_src
,ip_dst
,src_port
,dst_port
,pi
->proto
);
151 // search through the bucket
152 for (cxt
= head
; cxt
!= NULL
; cxt
= cxt
->next
) {
156 // Two-way compare of given connection against connection table
158 if (CMP_CXT4(cxt
,IP4ADDR(ip_src
),src_port
,IP4ADDR(ip_dst
),dst_port
)){
159 // Client sends first packet (TCP/SYN - UDP?) hence this is a client
160 return cxt_update_client(cxt
, pi
);
161 } else if (CMP_CXT4(cxt
,IP4ADDR(ip_dst
),dst_port
,IP4ADDR(ip_src
),src_port
)) {
162 // This is a server (Maybe not when we start up but in the long run)
163 return cxt_update_server(cxt
, pi
);
165 } else if (af
== AF_INET6
) {
166 if (CMP_CXT6(cxt
,ip_src
,src_port
,ip_dst
,dst_port
)){
167 return cxt_update_client(cxt
, pi
);
168 } else if (CMP_CXT6(cxt
,ip_dst
,dst_port
,ip_src
,src_port
)){
169 return cxt_update_server(cxt
, pi
);
173 // bucket turned upside down didn't yeild anything. new connection
175 log_connection(cxt
, CX_NEW
);
177 /* * New connections are pushed on to the head of bucket[s_hash] */
180 // are we doubly linked?
186 /* * Return value should be 1, telling to do client service fingerprinting */
190 void reverse_pi_cxt(packetinfo
*pi
)
195 struct in6_addr tmp_ip
;
201 /* First we chang the cxt */
203 tmpFlags
= cxt
->s_tcpFlags
;
204 tmp_pkts
= cxt
->s_total_pkts
;
205 tmp_bytes
= cxt
->s_total_bytes
;
207 tmp_port
= cxt
->s_port
;
210 cxt
->s_tcpFlags
= cxt
->d_tcpFlags
;
211 cxt
->s_total_pkts
= cxt
->d_total_pkts
;
212 cxt
->s_total_bytes
= cxt
->d_total_bytes
;
213 cxt
->s_ip
= cxt
->d_ip
;
214 cxt
->s_port
= cxt
->d_port
;
217 cxt
->d_tcpFlags
= tmpFlags
;
218 cxt
->d_total_pkts
= tmp_pkts
;
219 cxt
->d_total_bytes
= tmp_bytes
;
221 cxt
->d_port
= tmp_port
;
223 /* Not taking any chances :P */
224 cxt
->c_asset
= cxt
->s_asset
= NULL
;
227 /* Then we change pi */
228 if (pi
->sc
== SC_CLIENT
)
235 This sub marks sessions as ENDED on different criterias:
237 XXX: May be the fugliest code in PRADS :-(
245 int cxstatus
= CX_NONE
;
246 time_t check_time
= time(NULL
);
248 log_rotate(check_time
);
249 for (iter
= 0; iter
< BUCKET_SIZE
; iter
++) {
251 while (cxt
!= NULL
) {
253 if (cxt
->proto
== IP_PROTO_TCP
) {
254 /* * FIN from both sides */
255 if (cxt
->s_tcpFlags
& TF_FIN
&& cxt
->d_tcpFlags
& TF_FIN
256 && (check_time
- cxt
->last_pkt_time
) > 5) {
258 } /* * RST from either side */
259 else if ((cxt
->s_tcpFlags
& TF_RST
260 || cxt
->d_tcpFlags
& TF_RST
)
261 && (check_time
- cxt
->last_pkt_time
) > 5) {
264 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
265 cxstatus
= CX_EXPIRE
;
269 else if (cxt
->proto
== IP_PROTO_UDP
270 && (check_time
- cxt
->last_pkt_time
) > 60) {
271 cxstatus
= CX_EXPIRE
;
274 else if (cxt
->proto
== IP_PROTO_ICMP
275 || cxt
->proto
== IP6_PROTO_ICMP
) {
276 if ((check_time
- cxt
->last_pkt_time
) > 60) {
277 cxstatus
= CX_EXPIRE
;
280 /* All Other protocols */
281 else if ((check_time
- cxt
->last_pkt_time
) > TCP_TIMEOUT
) {
282 cxstatus
= CX_EXPIRE
;
285 if (cxstatus
== CX_ENDED
|| cxstatus
== CX_EXPIRE
) {
286 /* remove from the hash */
288 cxt
->prev
->next
= cxt
->next
;
290 cxt
->next
->prev
= cxt
->prev
;
291 connection
*tmp
= cxt
;
293 log_connection(cxt
, cxstatus
);
298 del_connection(tmp
, &bucket
[iter
]);
309 void log_connection_all()
313 if(! (config
.cflags
& CONFIG_CXWRITE
))
315 for(i
= 0; i
< BUCKET_SIZE
; i
++) {
318 log_connection(cxt
, CX_HUMAN
);
324 void del_connection(connection
* cxt
, connection
** bucket_ptr
)
326 connection
*prev
= cxt
->prev
; /* OLDER connections */
327 connection
*next
= cxt
->next
; /* NEWER connections */
335 } else if (next
== NULL
) {
345 * Free and set to NULL
351 void end_all_sessions()
355 FILE *cxtFile
= NULL
;
357 log_rotate(time(NULL
));
358 for (cxkey
= 0; cxkey
< BUCKET_SIZE
; cxkey
++) {
360 while (cxt
!= NULL
) {
361 connection
*tmp
= cxt
;
363 log_connection(cxt
, CX_ENDED
);
365 del_connection(tmp
, &bucket
[cxkey
]);
367 bucket
[cxkey
] = NULL
;
371 if (cxtFile
!= NULL
) {
376 void cxt_log_buckets(int dummy
)
378 connection
*cxt
= NULL
;
379 FILE *logfile
= NULL
;
383 logfile
= fopen("/tmp/prads-buckets.log", "w");
387 dlog("Recieved SIGUSR1 - Dumping bucketlist to logfile\n");
388 for (i
= 0; i
< BUCKET_SIZE
; i
++) {
390 for (cxt
= bucket
[i
]; cxt
; cxt
= cxt
->next
)
393 fprintf(logfile
, "%d in bucket[%5d]\n", len
, i
);
402 /* vector comparisons to speed up cx tracking.
403 * meaning, compare source:port and dest:port at the same time.
405 * about vectors and potential improvements:
406 * * all 64bit machines have at least SSE2 instructions * *BUT* there is no guarantee we won't loose time on
407 * copying the vectors around.
408 * ... indeed, a quick objdump shows us that
409 * there is a shitton of mov instructions to align the addresses.
411 * Needs support to give improvements:
412 * the addresses should already be aligned as a 128-bit word
413 * in the connection tracking bucket.
415 * note, we can employ the same technique for ipv6 addresses, but
416 * one address at a time.
418 #ifdef VECTOR_CXTRACKER
419 // vector fill: srcprt,dstprt,srcip,dstip = 96 bytes. rest is 0
420 #define VEC_FILL(vec, _ipsrc,_ipdst,_portsrc,_portdst) do {\
421 vec.s[0] = (_portsrc); \
422 vec.s[1] = (_portdst); \
423 vec.w[1] = (_ipsrc); \
424 vec.w[2] = (_ipdst); \
428 inline void cx_track_simd_ipv4(packetinfo
*pi
)
430 connection
*cxt
= NULL
;
431 connection
*head
= NULL
;
434 // add to packetinfo ? dont through int32 around :)
435 hash
= make_hash(pi
);
442 pi
->ip_src
.__u6_addr
.__u6_addr32
[0],
443 pi
->ip_dst
.__u6_addr
.__u6_addr32
[0],
446 while (cxt
!= NULL
) {
448 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
449 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
453 // single-instruction compare -msse2
454 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
455 // same thing, really. c == v iff c ^ v == 0
456 //compare.v = compare.v ^ incoming.v;
458 // 64-bit compare reduce
459 if(!(compare
.i
[0] & compare
.i
[1])){
461 dlog("[*] Updating src connection: %lu\n",cxt
->cxid
);
462 cxt_update_src(cxt
,pi
);
466 // compare the other direction
468 cxt
->d_ip
.__u6_addr
.__u6_addr32
[0],
469 cxt
->s_ip
.__u6_addr
.__u6_addr32
[0],
473 compare
.v
= __builtin_ia32_pcmpeqd128(incoming
.v
,compare
.v
);
474 if(!(compare
.i
[0] & compare
.i
[1])){
475 dlog("[*] Updating dst connection: %lu\n",cxt
->cxid
);
476 cxt_update_dst(cxt
,pi
);
482 cxt
= (connection
*) connection_alloc();
483 //cxt = (connection *) calloc(1, sizeof(connection));
488 dlog("[*] New connection: %lu\n",cxt
->cxid
);
493 printf("[*] Error in session tracking...\n");