/* * Copyright (c) 2000-2004 QoSient, LLC * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifndef ArgusApp #define ArgusApp #endif #include #include #include #include u_char ArgusUpdateHTTPState (struct ArgusFlowStruct *, unsigned char *); u_char ArgusUpdateRTPState (struct ArgusFlowStruct *, unsigned char *); void ArgusUpdateAppState (struct ArgusFlowStruct *flowstr, unsigned char *state) { struct ArgusUserObject *user = NULL; struct ArgusUserDataObject *ArgusThisUser; struct ArgusIPFlow *ipflow = NULL; struct ArgusFlowStats *ArgusThisStat = NULL; int len = 0, thislen = 0, ArgusThisUserLength; ipflow = (struct ArgusIPFlow *) &flowstr->flow; if (ArgusThisLength > 0) { if (flowstr->state.rev == ArgusThisDir) ArgusThisStat = &flowstr->state.src; else ArgusThisStat = &flowstr->state.dst; ArgusThisStat->appbytes += ArgusThisLength; } if (*state == ARGUS_START) { flowstr->state.status &= ~ARGUS_CONNECTED; if ((len = getArgusUserDataLen()) > 0) { if ((user = (void *) ArgusCalloc (1, sizeof(*user))) != NULL) { if (flowstr->UserDSRBuffer != NULL) { if (((struct ArgusUserObject *)flowstr->UserDSRBuffer)->src.array != NULL) ArgusFree (((struct ArgusUserObject *)flowstr->UserDSRBuffer)->src.array); if (((struct ArgusUserObject *)flowstr->UserDSRBuffer)->dst.array != NULL) ArgusFree (((struct ArgusUserObject *)flowstr->UserDSRBuffer)->dst.array); ArgusFree(flowstr->UserDSRBuffer); } flowstr->UserDSRBuffer = user; if ((user->src.array = (char *) ArgusCalloc (1, len)) == NULL) ArgusLog (LOG_ERR, "ArgusUpdateAppState(0x%x, %d) ArgusCalloc failed %s", strerror(errno)); user->src.count = 0; user->src.size = len; if ((user->dst.array = (char *) ArgusCalloc (1, len)) == NULL) ArgusLog (LOG_ERR, "ArgusUpdateAppState(0x%x, %d) ArgusCalloc failed %s", strerror(errno)); user->dst.count = 0; user->dst.size = len; } if (flowstr->state.rev == ArgusThisDir) ArgusThisUser = &user->src; else ArgusThisUser = &user->dst; ArgusThisUserLength = (ArgusThisLength < ArgusSnapLength) ? ArgusThisLength : ArgusSnapLength; if ((thislen = (ArgusThisUserLength < (ArgusThisUser->size - ArgusThisUser->count)) ? ArgusThisUserLength : (ArgusThisUser->size - ArgusThisUser->count)) > 0) { if (BYTESCAPTURED(ArgusThisUpHdr, thislen)) { bcopy (ArgusThisUpHdr, (char *)&ArgusThisUser->array[ArgusThisUser->count], thislen); ArgusThisUser->count += thislen; } } } } else { if ((user = (struct ArgusUserObject *) flowstr->UserDSRBuffer) != NULL) { if (flowstr->state.rev == ArgusThisDir) { ArgusThisUser = &user->src; } else ArgusThisUser = &user->dst; ArgusThisUserLength = (ArgusThisLength < ArgusSnapLength) ? ArgusThisLength : ArgusSnapLength; if (ArgusThisUser->count < ArgusThisUser->size) { if ((thislen = (ArgusThisUserLength < (ArgusThisUser->size - ArgusThisUser->count)) ? ArgusThisUserLength : (ArgusThisUser->size - ArgusThisUser->count)) > 0) { if (BYTESCAPTURED(ArgusThisUpHdr, thislen)) { bcopy (ArgusThisUpHdr, (char *)&ArgusThisUser->array[ArgusThisUser->count], thislen); ArgusThisUser->count += thislen; } } } } if (flowstr->state.src.count && flowstr->state.dst.count) flowstr->state.status |= ARGUS_CONNECTED; else flowstr->state.status &= ~ARGUS_CONNECTED; } if (ArgusThisIpHdr && ((ArgusThisNetworkFlowType & 0xFFFF) == ETHERTYPE_IP)) { if (*state == ARGUS_START) { struct rtphdr *rtp; struct rtcphdr *rtcp; #if defined(LBL_ALIGN) if ((long) ArgusThisUpHdr & (sizeof (long) - 1)) { bcopy ((unsigned char *) ArgusThisUpHdr, (unsigned char *) ArgusAlignBuf, ArgusSnapLength); ArgusThisUpHdr = (unsigned char *) ArgusAlignBuf; ArgusThisSnapEnd = ArgusAlignBuf + ArgusSnapLength; } #endif rtp = (struct rtphdr *) ArgusThisUpHdr; rtcp = (struct rtcphdr *) ArgusThisUpHdr; if (STRUCTCAPTURED(*rtp) && (rtp->rh_ver == 2)) { if ((rtcp->rh_pt == 200) || (rtcp->rh_pt == 201)) { struct ArgusRTCPObject *rtcpObject = NULL; ipflow->tp_p = ARGUS_RTCP_FLOWTAG; if ((rtcpObject = (void *) ArgusCalloc(1, sizeof(struct ArgusRTCPObject))) != NULL) { rtcpObject->type = ARGUS_RTCP_DSR; rtcpObject->length = sizeof(*rtcpObject); rtcpObject->status = ARGUS_START; if (flowstr->state.rev == ArgusThisDir) { bcopy ((char *) rtcp, (char *)&rtcpObject->src, sizeof(*rtcp)); rtcpObject->src.rh_len = ntohs(rtcpObject->src.rh_len); rtcpObject->src.rh_ssrc = ntohl(rtcpObject->src.rh_ssrc); } else { bcopy ((char *) rtcp, (char *)&rtcpObject->dst, sizeof(*rtcp)); rtcpObject->dst.rh_len = ntohs(rtcpObject->dst.rh_len); rtcpObject->dst.rh_ssrc = ntohl(rtcpObject->dst.rh_ssrc); } if (flowstr->TransportDSRBuffer != NULL) ArgusFree(flowstr->TransportDSRBuffer); flowstr->TransportDSRBuffer = rtcpObject; } } else if (rtp->rh_pt < 128) { struct ArgusRTPObject *rtpObject = NULL; ipflow->tp_p = ARGUS_RTP_FLOWTAG; if ((rtpObject = (void *) ArgusCalloc(1, sizeof(struct ArgusRTPObject))) != NULL) { rtpObject->type = ARGUS_RTP_DSR; rtpObject->length = sizeof(*rtpObject); rtpObject->status = ARGUS_START; if (flowstr->state.rev == ArgusThisDir) { bcopy ((char *) rtp, (char *)&rtpObject->src, sizeof(*rtp)); rtpObject->src.rh_seq = ntohs(rtpObject->src.rh_seq); rtpObject->src.rh_time = ntohl(rtpObject->src.rh_time); rtpObject->src.rh_ssrc = ntohl(rtpObject->src.rh_ssrc); } else { bcopy ((char *) rtp, (char *)&rtpObject->dst, sizeof(*rtp)); rtpObject->dst.rh_seq = ntohs(rtpObject->dst.rh_seq); rtpObject->dst.rh_time = ntohl(rtpObject->dst.rh_time); rtpObject->dst.rh_ssrc = ntohl(rtpObject->dst.rh_ssrc); } if (flowstr->TransportDSRBuffer != NULL) ArgusFree(flowstr->TransportDSRBuffer); flowstr->TransportDSRBuffer = rtpObject; } } } } else { if (ipflow->tp_p == 0) { } else { switch (ipflow->tp_p) { case ARGUS_HTTP_FLOWTAG: ArgusUpdateHTTPState(flowstr, state); break; case ARGUS_RTP_FLOWTAG: case ARGUS_RTCP_FLOWTAG: ArgusUpdateRTPState(flowstr, state); break; default: break; } } } } #ifdef ARGUSDEBUG ArgusDebug (6, "ArgusUpdateAppState(0x%x, %d) returning\n", flowstr, state); #endif } u_char ArgusUpdateHTTPState (struct ArgusFlowStruct *flowstr, unsigned char *state) { u_char retn = 0; #ifdef ARGUSDEBUG ArgusDebug (7, "ArgusUpdateHTTPState(0x%x, %d) returning\n", flowstr, state); #endif return(retn); } u_char ArgusUpdateRTPState (struct ArgusFlowStruct *flowstr, unsigned char *state) { u_char retn = 0; struct ArgusIPFlow *ipflow = NULL; ipflow = (struct ArgusIPFlow *) &flowstr->flow; switch (ipflow->tp_p) { case ARGUS_RTP_FLOWTAG: { struct ArgusRTPObject *rtpObject = (struct ArgusRTPObject *) flowstr->TransportDSRBuffer; struct rtphdr *rtp = (struct rtphdr *) ArgusThisUpHdr; struct rtphdr *ArgusThisRtpHdr = NULL; if (rtpObject && (STRUCTCAPTURED(*rtp) && !((long) rtp & (sizeof (short) - 1)))) { if (flowstr->state.rev == ArgusThisDir) ArgusThisRtpHdr = &rtpObject->src; else ArgusThisRtpHdr = &rtpObject->dst; if (rtp->rh_ver == 2) { rtp->rh_seq = ntohs(rtp->rh_seq); rtp->rh_time = ntohl(rtp->rh_time); rtp->rh_ssrc = ntohl(rtp->rh_ssrc); if (ArgusThisRtpHdr->rh_ver != 2) { bcopy ((char *) rtp, (char *) ArgusThisRtpHdr, sizeof(*rtp)); } else { if (!(rtp->rh_ssrc) || (ArgusThisRtpHdr->rh_ssrc != rtp->rh_ssrc)) ipflow->tp_p = 0; if (ArgusThisRtpHdr->rh_seq == (rtp->rh_seq)) ipflow->tp_p = 0; if (rtp->rh_x) { struct rtpexthdr *xhdr = (struct rtpexthdr *) (rtp + 1); if ((xhdr->length > ArgusThisLength) || (xhdr->length < (ArgusThisLength - 4))) ipflow->tp_p = 0; } } if (ipflow->tp_p == ARGUS_RTP_FLOWTAG) { int offset = ((rtp->rh_cc > 15) ? 15 : rtp->rh_cc) << 2; if (ArgusThisRtpHdr->rh_seq != (rtp->rh_seq - 1)) { if (rtp->rh_seq < ArgusThisRtpHdr->rh_seq) { if ((ArgusThisRtpHdr->rh_seq - rtp->rh_seq) < 0x7FFFFFFF) { if (flowstr->state.rev == ArgusThisDir) { if (rtpObject->sdrop > 0) { rtpObject->sdrop--; } } else { if (rtpObject->ddrop > 0) { rtpObject->ddrop--; } } } } else { if (rtp->rh_seq > ArgusThisRtpHdr->rh_seq) { if (flowstr->state.rev == ArgusThisDir) rtpObject->sdrop += rtp->rh_seq - (ArgusThisRtpHdr->rh_seq + 1); else rtpObject->ddrop += rtp->rh_seq - (ArgusThisRtpHdr->rh_seq + 1); } } } bcopy ((char *) rtp, (char *) ArgusThisRtpHdr, sizeof(*rtp)); ArgusThisUpHdr = (unsigned char *)(rtp + 1) + offset; ArgusThisLength -= (sizeof(struct rtphdr) + offset); ArgusSnapLength -= (sizeof(struct rtphdr) + offset); rtpObject->status &= ~ARGUS_START; if (rtp->rh_x) { struct rtpexthdr *ext = (struct rtpexthdr *)ArgusThisUpHdr; offset = sizeof(struct rtpexthdr) + ntohs(ext->length); ArgusThisLength -= offset; ArgusSnapLength -= offset; ArgusThisUpHdr += offset; } switch (rtp->rh_pt) { case ARGUS_RTP_PCMU: case ARGUS_RTP_PCMA: case ARGUS_RTP_G722: case ARGUS_RTP_G728: case ARGUS_RTP_G729: if ((ArgusThisLength == 0) || ((ArgusThisLength % 10) != 0)) { ArgusInProtocol = 0; if (flowstr->state.rev == ArgusThisDir) rtpObject->status |= ARGUS_RTP_SRCSILENCE; else rtpObject->status |= ARGUS_RTP_DSTSILENCE; } else if (rtp->rh_mark) ArgusInProtocol = 0; break; case ARGUS_RTP_G723: if ((ArgusThisLength == 0) || (ArgusThisLength == 4)) { ArgusInProtocol = 0; if (flowstr->state.rev == ArgusThisDir) rtpObject->status |= ARGUS_RTP_SRCSILENCE; else rtpObject->status |= ARGUS_RTP_DSTSILENCE; } else if (rtp->rh_mark) ArgusInProtocol = 0; break; case ARGUS_RTP_H261: case ARGUS_RTP_H263: break; } } else { ArgusFree(flowstr->TransportDSRBuffer); flowstr->TransportDSRBuffer = NULL; } } else ipflow->tp_p = 0; break; } else ipflow->tp_p = 0; } case ARGUS_RTCP_FLOWTAG: { struct ArgusRTCPObject *rtcpObject = (struct ArgusRTCPObject *) flowstr->TransportDSRBuffer; struct rtcphdr *rtcp = (struct rtcphdr *) ArgusThisUpHdr; struct rtcphdr *ArgusThisRtcpHdr = NULL; if (rtcpObject != NULL) { if (flowstr->state.rev == ArgusThisDir) ArgusThisRtcpHdr = &rtcpObject->src; else ArgusThisRtcpHdr = &rtcpObject->dst; if (rtcpObject && (STRUCTCAPTURED(*rtcp) && !((long) rtcp & (sizeof (short) - 1)))) { if (rtcp->rh_ver == 2) { if (ArgusThisRtcpHdr->rh_ssrc == 0) { bcopy ((char *) rtcp, (char *) ArgusThisRtcpHdr, sizeof(*rtcp)); ArgusThisRtcpHdr->rh_len = ntohs(ArgusThisRtcpHdr->rh_len); ArgusThisRtcpHdr->rh_ssrc = ntohl(ArgusThisRtcpHdr->rh_ssrc); if (ArgusThisRtcpHdr->rh_ssrc == 0) ipflow->tp_p = 0; } else if (ArgusThisRtcpHdr->rh_ssrc != ntohl(rtcp->rh_ssrc)) ipflow->tp_p = 0; } else ipflow->tp_p = 0; if (ipflow->tp_p == ARGUS_RTCP_FLOWTAG) rtcpObject->status &= ~ARGUS_START; } } } } if ((ipflow->tp_p == 0) && (flowstr->TransportDSRBuffer != NULL)) { ArgusFree(flowstr->TransportDSRBuffer); flowstr->TransportDSRBuffer = NULL; } #ifdef ARGUSDEBUG ArgusDebug (7, "ArgusUpdateRTPState(0x%x, %d) returning\n", flowstr, state); #endif return(retn); } #include void ArgusUserDataFlowRecord (struct ArgusFlowStruct *flow, struct ArgusRecord *argus, unsigned char state) { struct ArgusUserObject *user = (struct ArgusUserObject *) flow->UserDSRBuffer; struct ArgusUserStruct *buf; short length; int len; if (user && ((length = argus->ahdr.length) > 0)) { if ((len = user->src.count) > 0) { len = (((len + 3)/4) * 4); if ((buf = (void *) ArgusCalloc (1, 4 + user->src.count)) != NULL) { buf->type = ARGUS_SRCUSRDATA_DSR; buf->length = (4 + len) / 4; bcopy (user->src.array, &buf->data, user->src.count); bcopy ((char *)buf, &((char *)argus)[argus->ahdr.length], (buf->length * 4)); argus->ahdr.length += (buf->length * 4); ArgusFree(buf); } } if ((len = user->dst.count) > 0) { len = (((len + 3)/4) * 4); if ((buf = (void *) ArgusCalloc (1, 4 + user->dst.count)) != NULL) { buf->type = ARGUS_DSTUSRDATA_DSR; buf->length = (4 + len) / 4; bcopy (user->dst.array, &buf->data, user->dst.count); bcopy ((char *)buf, &((char *)argus)[argus->ahdr.length], (buf->length * 4)); argus->ahdr.length += (buf->length * 4); ArgusFree(buf); } } if (user->src.array) ArgusFree(user->src.array); if (user->dst.array) ArgusFree(user->dst.array); ArgusFree(flow->UserDSRBuffer); flow->UserDSRBuffer = NULL; } }