void traffic_read( struct ip *pip, /* the packet */ tcp_pair *ptp, /* info I have about this connection */ void *plast, /* past byte in the packet */ void *mod_data) /* connection info for this one */ { struct tcphdr *ptcp = (struct tcphdr *) ((char *)pip + 4*IP_HL(pip)); struct traffic_info *pti1 = FindPort(ntohs(ptcp->th_sport)); struct traffic_info *pti2 = FindPort(ntohs(ptcp->th_dport)); u_long bytes = ntohs(pip->ip_len); static timeval last_time = {0,0}; struct conn_info *pci = mod_data; int was_rexmit = 0; /* in case files aren't set up yet */ traffic_init_files(); /* if neither port is interesting, then ignore this one */ if (!pti1 && !pti2) { return; } /* OK, this connection is now active */ pci->wasactive = 1; /* check to see if it's really "open" (traffic in both directions) */ if (!pci->wasopen) { if ((ptp->a2b.packets > 0) && (ptp->b2a.packets > 0)) { /* bidirectional: OK, we'll call it open */ pci->wasopen = 1; pci->isopen = 1; ++num_opens; ++ttl_num_opens; ++open_conns; /* instantaneous opens and closes */ if (doplot_i_open) { DoplotIOpen(ntohs(ptcp->th_dport), TRUE); DoplotIOpen(ntohs(ptcp->th_sport), TRUE); DoplotIOpen(0, TRUE); } } } /* add to port-specific counters */ if (pti1) { pti1->nbytes += bytes; pti1->npackets += 1; } if (pti2) { pti2->nbytes += bytes; pti2->npackets += 1; } /* add to GLOBAL counters */ ports[0]->nbytes += bytes; ports[0]->npackets += 1; ports[0]->npureacks += 1; /* see if we're closing it */ if (RESET_SET(ptcp) || (FIN_SET(ptcp) && /* find in BOTH directions */ ((ptp->a2b.fin_count>0) && (ptp->b2a.fin_count>0)))) { if (pci->isopen) { pci->isopen = 0; ++num_closes; --open_conns; /* instantaneous opens and closes */ if (doplot_i_open) { DoplotIOpen(ntohs(ptcp->th_dport), FALSE); DoplotIOpen(ntohs(ptcp->th_sport), FALSE); DoplotIOpen(0, FALSE); } } } /* half open conns */ if (FIN_SET(ptcp)) { if ((ptp->a2b.fin_count>0) && (ptp->b2a.fin_count>0)) { if (pci->halfopen) { /* fully closed now */ --num_halfopens; pci->halfopen = 0; } } else if (!pci->halfopen) { /* half open now */ ++num_halfopens; pci->halfopen = 1; } } /* check losses */ if (pci->last_dupacks != ptp->a2b.rtt_triple_dupack+ ptp->b2a.rtt_triple_dupack) { pci->last_dupacks = ptp->a2b.rtt_triple_dupack+ ptp->b2a.rtt_triple_dupack; ++dupacks; ++ttl_dupacks; } if (pci->last_rexmits != ptp->a2b.rexmit_pkts+ptp->b2a.rexmit_pkts) { pci->last_rexmits = ptp->a2b.rexmit_pkts+ptp->b2a.rexmit_pkts; was_rexmit = 1; ++rexmits; ++ttl_rexmits; } /* add to total data counters */ data_nbytes_all += bytes; if (!was_rexmit) data_nbytes_nonrexmit += bytes; /* RTT stats */ if (ACK_SET(ptcp)) { tcb *ptcb; int rtt; /* see which of the 2 TCB's this goes with */ if (ptp->addr_pair.a_port == ntohs(ptcp->th_dport)) ptcb = &ptp->a2b; else ptcb = &ptp->b2a; /* check the rtt counter of the last sample */ rtt = ptcb->rtt_last / 1000.0; if ((pci->last_rtts != ptcb->rtt_count + ptcb->rtt_amback) && (ptcb->rtt_last != 0.0) && (rtt > rtt_minvalid) && (rtt <= rtt_maxvalid)) { /* sample is only valid when one of these counters is higher */ pci->last_rtts = ptcb->rtt_count + ptcb->rtt_amback; /* keep stats */ rtt_ttl += rtt; ttl_rtt_ttl += rtt; ++rtt_samples; ++ttl_rtt_samples; /* also, remember min and max */ if ((rtt_max == -1) || (rtt_max < rtt)) rtt_max = rtt; if ((rtt_min == -1) || (rtt_min > rtt)) rtt_min = rtt; if (ldebug > 9) printf("Rtt: %d, min:%d, max:%d\n", rtt, rtt_min, rtt_max); } } /* see if this is now "long duration" */ if (!pci->islong) { int etime_msecs = elapsed(ptp->first_time,current_time); if (etime_msecs/1000000 > longconn_duration) { pci->islong = 1; } } /* count "pure acks" (no data) */ if (ACK_SET(ptcp)) { int tcp_length, tcp_data_length; tcp_length = getpayloadlength(pip, plast); tcp_data_length = tcp_length - (4 * TH_OFF(ptcp)); if (tcp_data_length == 0) { if (pti1) { ++pti1->npureacks; } if (pti2) { ++pti2->npureacks; } } } /* determine elapsed time and age the samples */ if (elapsed(last_time,current_time)/1000000.0 > age_interval) { AgeTraffic(); last_time = current_time; } }
void dump_flow_stat (struct ip *pip, void *pproto, int tproto, void *pdir, int dir, void *hdr, void *plast) { int ucb_type; if (!dump_engine) return; if (threaded) pthread_mutex_lock(&dump_mutex); /***** TCP packets *****/ if (tproto == PROTOCOL_TCP) /* It's TCP, there is still a flow associated to this, and we are not already discarding it */ { struct stcp_pair *p = ((tcb *)pdir)->ptp; if (proto2dump[DUMP_TCP_COMPLETE].enabled && (p != NULL) && !(p->stop_dumping_tcp) ) { /* are we still interested in this flow packets? */ if ( ( p->con_type != UNKNOWN_PROTOCOL ) /* we always log unknowns */ && ( (p->con_type & stop_dumping_mask) != 0 ) /* after masking, we are not interested into it */ ) { p->stop_dumping_tcp = TRUE; if (debug>0) { fprintf(fp_stderr, "Stopping dumping this flow - con_type = %d\n",p->con_type); } } if (!(p->stop_dumping_tcp)) { /* do we have to dump all the packets of all the flows */ if (tcp_maxbytes == 0 && tcp_maxpackets == 0) { dump_to_file(&proto2dump[DUMP_TCP_COMPLETE], pip, plast); } /* or we have to stop dumping acks and data packets up to reach * - tcp_maxbytes * - tcp_maxpackets */ else { struct tcphdr *ptcp = pproto; /* check if the underlying flow struct tcb has not yet been released */ if ( p != NULL) { int tcp_data_length = getpayloadlength (pip, plast) - (4 * ptcp->th_off); tcb *thisdir = (tcb*)pdir; tcb *otherdir = (dir == C2S) ? &(thisdir->ptp->s2c) : &(thisdir->ptp->c2s); if (( /* packets with payload */ tcp_data_length > 0 && /* check the thresholds */ ((tcp_maxbytes > 0 && thisdir->seq - thisdir->syn - tcp_data_length <= tcp_maxbytes) || (tcp_maxpackets > 0 && thisdir->data_pkts <= tcp_maxpackets)) ) || ( /* this is a pure ack */ tcp_data_length == 0 && (otherdir->seq <= thisdir->ack && /* which is a valid ack */ ( /* and we are still interested in otherdir packets */ (tcp_maxbytes > 0 && otherdir->seq - otherdir->syn <= tcp_maxbytes) || (tcp_maxpackets > 0 && otherdir->data_pkts <= tcp_maxpackets) || (otherdir->fin_count >= 1 && thisdir->ack >= (otherdir->fin_seqno+1)) )) ) || SYN_SET (ptcp) || FIN_SET(ptcp) ) { dump_to_file(&proto2dump[DUMP_TCP_COMPLETE], pip, plast); } } else { if (RESET_SET(ptcp)) { dump_to_file(&proto2dump[DUMP_TCP_COMPLETE], pip, plast); } } } } /* end !stop_dumping_tcp */ } /* end DUMP_TCP_COMPLETE */ #ifdef STREAMING_CLASSIFIER if (proto2dump[DUMP_TCP_VIDEOSTREAMING].enabled && ((tcb*)pdir)->ptp != NULL) { struct stcp_pair *p = ((tcb *)pdir)->ptp; if (p->streaming.video_content_type || p->streaming.video_payload_type) { dump_to_file(&proto2dump[DUMP_TCP_VIDEOSTREAMING], pip, plast); } } #endif } /***** UDP packets *****/ else { ucb *mydir = (ucb*)pdir; //specific controls to find kad obfuscated... ucb_type = UDP_p2p_to_logtype(mydir); /* dump to a specific DPI file */ if (proto2dump[P2P_UTP].enabled) { /* Since uTP classification is behavioral, we dump both already classified datagrams, and datagrams which are not classified, but that are already in a valid state of the identification state machine. */ if ( ucb_type == P2P_UTP || ucb_type == P2P_UTPBT || ( (ucb_type==UDP_UNKNOWN || ucb_type==FIRST_RTP || ucb_type==FIRST_RTCP || ucb_type==P2P_BT) && (mydir->uTP_state > UTP_UNKNOWN ) ) ) dump_to_file(&proto2dump[P2P_UTP], pip, plast); } else if (proto2dump[ucb_type].enabled) { dump_to_file(&proto2dump[ucb_type], pip, plast); } // dump to unknown // else if (proto2dump[UDP_UNKNOWN].enabled) { // dump_to_file(&proto2dump[UDP_UNKNOWN], pip, plast); // } if (proto2dump[DUMP_UDP_COMPLETE].enabled) { /* dump all the packets of all the flows */ if (udp_maxpackets == 0 && udp_maxbytes == 0) { dump_to_file(&proto2dump[DUMP_UDP_COMPLETE], pip, plast); } else { /* check if the underlying flow struct ucb has not yet been released */ if (((ucb*)pdir)->pup != NULL) { ucb *thisdir = (ucb*)pdir; /* dump acks and data packets up to reach * - udp_maxbytes * - udp_maxpackets */ if ( (thisdir->data_bytes <= udp_maxbytes) || (thisdir->packets <= udp_maxpackets)) { dump_to_file(&proto2dump[DUMP_UDP_COMPLETE], pip, plast); } } else /* it shouldn't happen, but in case dump the packet in any case */ dump_to_file(&proto2dump[DUMP_UDP_COMPLETE], pip, plast); } } } if (threaded) pthread_mutex_unlock(&dump_mutex); }