diff options
author | Gerald Begumisa <ben_g@users.sourceforge.net> | 2007-02-06 06:56:19 +0000 |
---|---|---|
committer | Gerald Begumisa <ben_g@users.sourceforge.net> | 2007-02-06 06:56:19 +0000 |
commit | 6ea47988e23c732814f792cb9dde7a35f9b26885 (patch) | |
tree | 886a952c4570e6d62d44bac3bdd9999daaf1ecfc /orkaudio/audiocaptureplugins/voip/VoIp.cpp | |
parent | 94e3eb2d0cda7df2d876d1698db2e8e75cd0a0b1 (diff) |
IAX2 support added by Gerald Begumisa
git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@399 09dcff7a-b715-0410-9601-b79a96267cd0
Diffstat (limited to 'orkaudio/audiocaptureplugins/voip/VoIp.cpp')
-rw-r--r-- | orkaudio/audiocaptureplugins/voip/VoIp.cpp | 835 |
1 files changed, 825 insertions, 10 deletions
diff --git a/orkaudio/audiocaptureplugins/voip/VoIp.cpp b/orkaudio/audiocaptureplugins/voip/VoIp.cpp index ab3de80..ef6807f 100644 --- a/orkaudio/audiocaptureplugins/voip/VoIp.cpp +++ b/orkaudio/audiocaptureplugins/voip/VoIp.cpp @@ -37,6 +37,7 @@ #include "PacketHeaderDefs.h" #include "Rtp.h" #include "RtpSession.h" +#include "Iax2Session.h" extern AudioChunkCallBackFunction g_audioChunkCallBack; extern CaptureEventCallBackFunction g_captureEventCallBack; @@ -204,11 +205,765 @@ char* GrabLine(char* start, char* limit, CStdString& out) return c; } +static int iax2_codec_to_rtp_payloadtype(int codec) +{ + switch(codec) { + case IAX2_CODEC_ULAW: + return 0; + case IAX2_CODEC_G726: + return 2; + case IAX2_CODEC_GSM: + return 3; + case IAX2_CODEC_G723_1: + return 4; + case IAX2_CODEC_ADPCM: + return 5; + case IAX2_CODEC_LPC10: + return 7; + case IAX2_CODEC_ALAW: + return 8; + case IAX2_CODEC_SLINEAR: + return 9; + case IAX2_CODEC_G729A: + return 18; + case IAX2_CODEC_ILBC: + return 97; + default: + return -1; + } + + /* NOT REACHED */ + return -1; +} + +static int get_uncompressed_subclass(unsigned char c_sub) +{ + if (c_sub & 0x80) { + /* 'C' bit is set (refer to standard) */ + if (c_sub == 0xFF) + return -1; + else + return 1 << (c_sub & ~0x80 & 0x1F); + } else { + /* 'C' bit in SubClass component not set */ + return c_sub; + } +} + +static int parse_iax2_ies(struct iax2_ies *ies, unsigned char *data, int datalen) +{ + int len = 0, ie = 0, odlen = datalen, pass=1; + CStdString logmsg; + + memset(ies, 0, (int)sizeof(struct iax2_ies)); + while(datalen >= 2) { + ie = data[0]; + len = data[1]; + + //logmsg.Format("Looking up IE %d (len=%d)", ie, len); + //LOG4CXX_INFO(s_packetLog, logmsg); + + if (len > datalen - 2) { + /* Strange. The quoted length of the IE is past the actual + * bounds of the IEs size */ + logmsg.Format("Error parsing IEs Pass=%d Length of IE=%d, " + "datalen-2=%d, IE=%d, OrigDlen=%d", pass, len, datalen-2, ie, odlen); + LOG4CXX_INFO(s_packetLog, logmsg); + return -1; + } + + switch(ie) { + case IAX2_IE_CALLED_NUMBER: + ies->callee = (char *)data + 2; + break; + case IAX2_IE_CALLING_NUMBER: + ies->caller = (char *)data + 2; + break; + case IAX2_IE_FORMAT: + if(len == (int)sizeof(unsigned int)) + ies->format = ntohl(get_unaligned_uint32(data+2)); + else + ies->format = 0; /* Invalid */ + break; + case IAX2_IE_USERNAME: + ies->username = (char *)data + 2; + break; + case IAX2_IE_AUTHMETHODS: + if(len == (int)sizeof(unsigned int)) + ies->authmethods = ntohl(get_unaligned_uint32(data+2)); + else + ies->authmethods = 0; /* Invalid */ + break; + case IAX2_IE_CHALLENGE: + ies->challenge = (char *)data + 2; + break; + default: + /* Ignore the rest */ + break; + } + +#if 0 /* Debug headaches caused by udpHeader->len */ + char tmpt[256]; + memset(tmpt, 0, sizeof(tmpt)); + memcpy(tmpt, data+2, len); + logmsg.Format("Got %s", tmpt); + LOG4CXX_INFO(s_packetLog, logmsg); +#endif + + data[0] = 0; + datalen -= (len + 2); + data += (len + 2); + pass++; + } + + *data = '\0'; + if(datalen) { + /* IE contents likely to be invalid because we should have totally + * consumed the entire amount of data */ + CStdString logmsg; + + logmsg.Format("Error parsing IEs. datalen left=%d", len, datalen, ie); + LOG4CXX_INFO(s_packetLog, logmsg); + + return -1; + } + + return 0; +} + +void iax2_dump_frame(struct Iax2FullHeader *fh, char *source, char *dest) +{ + const char *frames[] = { + "(0?)", + "DTMF ", + "VOICE ", + "VIDEO ", + "CONTROL", + "NULL ", + "IAX ", + "TEXT ", + "IMAGE ", + "HTML ", + "CNG " }; + const char *iaxs[] = { + "(0?)", + "NEW ", + "PING ", + "PONG ", + "ACK ", + "HANGUP ", + "REJECT ", + "ACCEPT ", + "AUTHREQ", + "AUTHREP", + "INVAL ", + "LAGRQ ", + "LAGRP ", + "REGREQ ", + "REGAUTH", + "REGACK ", + "REGREJ ", + "REGREL ", + "VNAK ", + "DPREQ ", + "DPREP ", + "DIAL ", + "TXREQ ", + "TXCNT ", + "TXACC ", + "TXREADY", + "TXREL ", + "TXREJ ", + "QUELCH ", + "UNQULCH", + "POKE ", + "PAGE ", + "MWI ", + "UNSPRTD", + "TRANSFR", + "PROVISN", + "FWDWNLD", + "FWDATA " + }; + const char *cmds[] = { + "(0?)", + "HANGUP ", + "RING ", + "RINGING", + "ANSWER ", + "BUSY ", + "TKOFFHK", + "OFFHOOK" }; + char class2[20]; + char subclass2[20]; + CStdString tmp; + const char *cclass; + const char *subclass; + char *dir; + + if (fh->type >= (int)sizeof(frames)/(int)sizeof(frames[0])) { + snprintf(class2, sizeof(class2), "(%d?)", fh->type); + cclass = class2; + } else { + cclass = frames[(int)fh->type]; + } + + if (fh->type == IAX2_FRAME_IAX) { + if (fh->c_sub >= (int)sizeof(iaxs)/(int)sizeof(iaxs[0])) { + snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->c_sub); + subclass = subclass2; + } else { + subclass = iaxs[(int)fh->c_sub]; + } + } else if (fh->type == IAX2_FRAME_CONTROL) { + if (fh->c_sub >= (int)sizeof(cmds)/(int)sizeof(cmds[0])) { + snprintf(subclass2, sizeof(subclass2), "(%d?)", fh->c_sub); + subclass = subclass2; + } else { + subclass = cmds[(int)fh->c_sub]; + } + } else { + snprintf(subclass2, sizeof(subclass2), "%d", fh->c_sub); + subclass = subclass2; + } + + tmp.Format("IAX2-Frame -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s", + fh->oseqno, fh->iseqno, cclass, subclass); + LOG4CXX_INFO(s_packetLog, tmp); + tmp.Format(" Timestamp: %05lums SCall: %5.5d DCall: %5.5d [Source: %s Dest: %s]", + (unsigned long)ntohl(fh->ts), + ntohs(fh->scallno) & ~0x8000, ntohs(fh->dcallno) & ~0x8000, source, dest); + + LOG4CXX_INFO(s_packetLog, tmp); +} + +/* See if this is an IAX2 NEW. If so, process */ +bool TryIax2New(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + struct iax2_ies ies; + int ies_len = 0, udp_act_payload_len = 0; + Iax2NewInfoRef info(new Iax2NewInfo()); + char source_ip[16], dest_ip[16]; + CStdString logmsg; + + memset(&ies, 0, sizeof(ies)); + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + ies_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + +#if 0 /* Debug headaches caused by udpHeader->len */ + /* Beware that udpHeader->len is not the length of the udpPayload + * but rather this includes the length of the UDP header as well. + * I.e watch out for the figure "8" as you debug ;-) */ + { + char source_ip[16], dest_ip[16]; + + ACE_OS::inet_ntop(AF_INET, (void*)&ipHeader->ip_src, source_ip, sizeof(source_ip)); + ACE_OS::inet_ntop(AF_INET, (void*)&ipHeader->ip_dest, dest_ip, sizeof(dest_ip)); + iax2_dump_frame(fh, source_ip, dest_ip); + } + + logmsg.Format("UDP_Payload=%p UDP+FH_Payload=%p FH->IEDATA=%p ies_len=%d " + "udpHeader->len-sizeof(fullhdr)=%d (ntohs(udpHeader->len)" + "-sizeof(UdpHeaderStruct))=%d", udpPayload, udpPayload+ + sizeof(*fh), fh->ie_data, ies_len, (ntohs(udpHeader->len)- + sizeof(*fh)), (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct))); + LOG4CXX_INFO(s_packetLog, logmsg); +#endif + + if(fh->type != IAX2_FRAME_IAX) + return false; /* Frame type must be IAX */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_COMMAND_NEW) + return false; /* Subclass must be NEW */ + + if(parse_iax2_ies(&ies, fh->ie_data, ies_len)) + return false; /* Invalid "full" frame received */ + + if(!ies.callee) + return false; /* According to the SPEC, a NEW MUST have a + * callee (Called Number) */ + + if(!strlen(ies.callee)) + return false; /* According to the SPEC, a NEW MUST have a + * callee (Called Number) */ + + if(!ies.caller) { + ies.caller = "WITHELD"; + } else { + if(!strlen(ies.caller)) { + ies.caller = "WITHELD"; + } + } + + /* Statistically this is most likely a NEW IAX2 frame. */ + + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_caller = CStdString(ies.caller); + info->m_callee = CStdString(ies.callee); + info->m_callNo = IntToString(ntohs(fh->scallno) & ~0x8000); + + /* Report the packet */ + Iax2SessionsSingleton::instance()->ReportIax2New(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 NEW frame"); + + return true; +} + +bool TryIax2Accept(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + struct iax2_ies ies; + int ies_len = 0, udp_act_payload_len = 0; + Iax2AcceptInfoRef info(new Iax2AcceptInfo()); + + memset(&ies, 0, sizeof(ies)); + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_IAX) + return false; /* Frame type must be IAX */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_COMMAND_ACCEPT) + return false; /* Subclass must be ACCEPT */ + + ies_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + + /* In this case, this just serves to test the integrity of the + * Information Elements */ + if(parse_iax2_ies(&ies, fh->ie_data, ies_len)) + return false; /* Invalid "full" frame received */ + + if(!ies.format) + return false; /* According to the SPEC, ACCEPT must have + * a format specified */ + + /* We have an ACCEPT */ + + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_sender_callno = IntToString(ntohs(fh->scallno) & ~0x8000); + info->m_receiver_callno = IntToString(ntohs(fh->dcallno) & ~0x8000); + + Iax2SessionsSingleton::instance()->ReportIax2Accept(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 ACCEPT frame"); + + return true; +} + +bool TryIax2Authreq(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + struct iax2_ies ies; + int ies_len = 0, udp_act_payload_len = 0; + Iax2AuthreqInfoRef info(new Iax2AuthreqInfo()); + + memset(&ies, 0, sizeof(ies)); + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_IAX) + return false; /* Frame type must be IAX */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_COMMAND_AUTHREQ) + return false; /* Subclass must be AUTHREQ */ + + ies_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + + /* In this case, this just serves to test the integrity of the + * Information Elements */ + if(parse_iax2_ies(&ies, fh->ie_data, ies_len)) + return false; /* Invalid "full" frame received */ + + + if(!ies.username) + return false; /* According to the spec AUTHREQ must have + * a user name. Can it be empty? */ + + /* + if(!strlen(ies.username)) + return false; * According to the spec AUTHREQ must have + * a user name. * + */ + + if(!ies.authmethods) + return false; /* According to the spec AUTHREQ must have + * AUTHMETHODS */ + + if(!ies.challenge) + return false; /* According to the spec, AUTHREQ must have + * a CHALLENGE string. Can it be empty? */ + + + /* We have an AUTHREQ */ + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_sender_callno = IntToString(ntohs(fh->scallno) & ~0x8000); + info->m_receiver_callno = IntToString(ntohs(fh->dcallno) & ~0x8000); + + /* Report the packet */ + Iax2SessionsSingleton::instance()->ReportIax2Authreq(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 AUTHREQ frame"); + + return true; +} + +/* HANGUP via IAX frame */ +bool TryIax2Hangup(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + struct iax2_ies ies; + int ies_len = 0, udp_act_payload_len = 0; + Iax2HangupInfoRef info(new Iax2HangupInfo()); + + memset(&ies, 0, sizeof(ies)); + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_IAX) + return false; /* Frame type must be IAX */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_COMMAND_HANGUP) + return false; /* Subclass must be HANGUP */ + + ies_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + + /* In this case, this just serves to test the integrity of the + * Information Elements */ + if(parse_iax2_ies(&ies, fh->ie_data, ies_len)) + return false; /* Invalid "full" frame received */ + + /* We have a HANGUP */ + + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_sender_callno = IntToString(ntohs(fh->scallno) & ~0x8000); + info->m_receiver_callno = IntToString(ntohs(fh->dcallno) & ~0x8000); + + /* Report the packet */ + Iax2SessionsSingleton::instance()->ReportIax2Hangup(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 HANGUP frame"); + + return true; +} + +/* HANGUP via CONTROL frame */ +bool TryIax2ControlHangup(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + Iax2HangupInfoRef info(new Iax2HangupInfo()); + int udp_act_payload_len = 0; + + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_CONTROL) + return false; /* Frame type must be CONTROL */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_CONTROL_HANGUP) + return false; /* Subclass must be HANGUP */ + + /* We have a HANGUP */ + + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_sender_callno = IntToString(ntohs(fh->scallno) & ~0x8000); + info->m_receiver_callno = IntToString(ntohs(fh->dcallno) & ~0x8000); + + /* Report the packet */ + Iax2SessionsSingleton::instance()->ReportIax2Hangup(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 CONTROL HANGUP frame"); + + return true; +} + +bool TryIax2Reject(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + struct iax2_ies ies; + int ies_len = 0, udp_act_payload_len = 0; + Iax2HangupInfoRef info(new Iax2HangupInfo()); + + memset(&ies, 0, sizeof(ies)); + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_IAX) + return false; /* Frame type must be IAX */ + + if(get_uncompressed_subclass(fh->c_sub) != IAX2_COMMAND_REJECT) + return false; /* Subclass must be REJECT */ + + ies_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + + /* In this case, this just serves to test the integrity of the + * Information Elements */ + if(parse_iax2_ies(&ies, fh->ie_data, ies_len)) + return false; /* Invalid "full" frame received */ + + /* We have a REJECT */ + + info->m_senderIp = ipHeader->ip_src; + info->m_receiverIp = ipHeader->ip_dest; + info->m_sender_callno = IntToString(ntohs(fh->scallno) & ~0x8000); + info->m_receiver_callno = IntToString(ntohs(fh->dcallno) & ~0x8000); + + /* Report the packet */ + Iax2SessionsSingleton::instance()->ReportIax2Hangup(info); + + LOG4CXX_INFO(s_packetLog, "Processed IAX2 REJECT frame"); + + return true; +} + +bool TryIax2FullVoiceFrame(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2FullHeader *fh = (struct Iax2FullHeader *)udpPayload; + int data_len = 0, codec = 0, pt = 0, udp_act_payload_len = 0; + Iax2PacketInfoRef info(new Iax2PacketInfo()); + + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*fh)) + return false; /* Frame too small */ + + if(!(ntohs(fh->scallno) & 0x8000)) + return false; /* Not a full frame */ + + if(fh->type != IAX2_FRAME_VOICE) + return false; /* Frame type must be VOICE */ + + codec = get_uncompressed_subclass(fh->c_sub); + if((pt = iax2_codec_to_rtp_payloadtype(codec)) < 0) { + CStdString logmsg; + + logmsg.Format("Invalid payload type %d received for " + "IAX_FRAME_VOICE, IAX2 codec %d", pt, codec); + LOG4CXX_INFO(s_packetLog, logmsg); + return false; /* Invalid codec type received */ + } + + data_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*fh)); + if(data_len == 0) + return false; /* Empty packet? */ + + /* We have a full VOICE frame */ + + info->m_sourceIp = ipHeader->ip_src; + info->m_destIp = ipHeader->ip_dest; + info->m_sourcecallno = (ntohs(fh->scallno) & ~0x8000); + info->m_destcallno = (ntohs(fh->dcallno) & ~0x8000); + info->m_payloadSize = data_len; + info->m_payload = udpPayload+sizeof(*fh); + info->m_payloadType = pt; + info->m_timestamp = ntohl(fh->ts); + info->m_arrivalTimestamp = time(NULL); + info->m_frame_type = IAX2_FRAME_FULL; + + Iax2SessionsSingleton::instance()->ReportIax2Packet(info); + + CStdString logmsg; + logmsg.Format("Processed IAX2 FULL VOICE fram, pt %d", pt); + LOG4CXX_INFO(s_packetLog, logmsg); + + return true; +} + +bool TryIax2MetaTrunkFrame(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2MetaTrunkHeader *mh = (struct Iax2MetaTrunkHeader *)udpPayload; + struct Iax2MetaTrunkEntry *supermini = NULL; + struct Iax2MetaTrunkEntryTs *mini = NULL; + int content_type = 0; /* 0 means mini frames, 1 means super mini (no timestampes) */ + int frame_ts = 0; /* Timestamp of frame */ + int data_len = 0; + int entries = 0, udp_act_payload_len = 0; + Iax2PacketInfoRef info(new Iax2PacketInfo()); + + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*mh)) + return false; /* Frame too small */ + + if(mh->meta != 0) + return false; /* Must be zero */ + + if(mh->metacmd & 0x80) + return false; /* 'V' bit must be set to zero */ + + if(mh->metacmd != 1) + return false; /* metacmd must be 1 */ + + /* Get the length of the information apart from the + * meta trunk header */ + data_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*mh)); + if(data_len == 0) + return false; /* Empty packet? */ + + /* Step over the meta trunk header */ + udpPayload += sizeof(*mh); + + /* Determine whether the trunk contents have their own + * timestamps or not */ + if(mh->cmddata & 0x01) + content_type = 1; + else + content_type = 0; + + if(content_type) { + /* Have timestamps */ + + while(data_len) { + if(data_len < sizeof(*mini)) + break; + + mini = (struct Iax2MetaTrunkEntryTs *)udpPayload; + + if(data_len < sizeof(*mini)+ntohs(mini->len)) + break; + + info->m_sourceIp = ipHeader->ip_src; + info->m_destIp = ipHeader->ip_dest; + info->m_sourcecallno = (ntohs(mini->mini.scallno) & ~0x8000); + info->m_destcallno = 0; + info->m_payloadSize = ntohs(mini->len); + info->m_payload = udpPayload+sizeof(*mini); + info->m_payloadType = 0; + info->m_timestamp = ntohs(mini->mini.ts); + info->m_arrivalTimestamp = time(NULL); + info->m_frame_type = IAX2_FRAME_MINI; + + Iax2SessionsSingleton::instance()->ReportIax2Packet(info); + entries += 1; + + udpPayload += sizeof(*mini)+ntohs(mini->len); + data_len -= sizeof(*mini)+ntohs(mini->len); + } + } else { + /* Have no timestamps */ + while(data_len) { + if(data_len < sizeof(*supermini)) + break; + + supermini = (struct Iax2MetaTrunkEntry *)udpPayload; + + if(data_len < sizeof(*supermini)+ntohs(supermini->len)) + break; + + info->m_sourceIp = ipHeader->ip_src; + info->m_destIp = ipHeader->ip_dest; + info->m_sourcecallno = (ntohs(supermini->scallno) & ~0x8000); + info->m_destcallno = 0; + info->m_payloadSize = ntohs(supermini->len); + info->m_payload = udpPayload+sizeof(*supermini); + info->m_payloadType = 0; + info->m_timestamp = 0; + info->m_arrivalTimestamp = time(NULL); + info->m_frame_type = IAX2_FRAME_MINI; + + Iax2SessionsSingleton::instance()->ReportIax2Packet(info); + entries += 1; + + udpPayload += sizeof(*supermini)+ntohs(supermini->len); + data_len -= sizeof(*supermini)+ntohs(supermini->len); + } + } + + + if(entries > 0) { + CStdString logmsg; + + logmsg.Format("Processed IAX2 Meta Trunk packet with %d entries", entries); + LOG4CXX_DEBUG(s_packetLog, logmsg); + return true; + } + + return false; /* No valid entries in this so-called meta trunk frame */ +} + +bool TryIax2MiniVoiceFrame(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, + UdpHeaderStruct* udpHeader, u_char* udpPayload) +{ + struct Iax2MiniHeader *mini = (struct Iax2MiniHeader *)udpPayload; + int data_len = 0, udp_act_payload_len = 0; + Iax2PacketInfoRef info(new Iax2PacketInfo()); + + udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + if(udp_act_payload_len < sizeof(*mini)) + return false; /* Frame too small */ + + if((ntohs(mini->scallno) & 0x8000)) + return false; /* Not a Mini frame */ + + data_len = ((u_char*)ipHeader+ntohs(ipHeader->ip_len))-(udpPayload+sizeof(*mini)); + if(data_len == 0) + return false; /* Empty packet? */ + + info->m_sourceIp = ipHeader->ip_src; + info->m_destIp = ipHeader->ip_dest; + info->m_sourcecallno = (ntohs(mini->scallno) & ~0x8000); + info->m_destcallno = 0; + info->m_payloadSize = data_len; + info->m_payload = udpPayload+sizeof(*mini); + info->m_payloadType = 0; + info->m_timestamp = ntohl(mini->ts); + info->m_arrivalTimestamp = time(NULL); + info->m_frame_type = IAX2_FRAME_MINI; + + Iax2SessionsSingleton::instance()->ReportIax2Packet(info); + + //LOG4CXX_INFO(s_packetLog, "Processed IAX2 Mini Voice packet"); + + return true; +} + bool TryRtp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload) { bool result = false; RtpHeaderStruct* rtpHeader = (RtpHeaderStruct*)udpPayload; + /* Ensure that the UDP payload is at least sizeof(RtpHeaderStruct) */ + if(ntohs(udpHeader->len) < sizeof(RtpHeaderStruct)) + return false; + if (rtpHeader->version == 2) { u_short source = ntohs(udpHeader->source); @@ -268,6 +1023,13 @@ bool TryRtp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpH bool TrySipBye(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload) { bool result = false; + int udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + + /* Judgine from the memcmp() below, we need the UDP payload + * length to be at least 3 bytes. -- Gerald */ + if(udp_act_payload_len < 3) + return false; /* Frame too small */ + if (memcmp("BYE", (void*)udpPayload, 3) == 0) { result = true; @@ -292,6 +1054,13 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader { bool result = false; bool drop = false; + int udp_act_payload_len = (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)); + + /* Judgine from the memcmp() below, we need the UDP payload + * length to be at least 3 bytes. -- Gerald */ + if(udp_act_payload_len < 6) + return false; /* Frame too small */ + if (memcmp("INVITE", (void*)udpPayload, 6) == 0) { result = true; @@ -655,21 +1424,66 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char { UdpHeaderStruct* udpHeader = (UdpHeaderStruct*)((char *)ipHeader + ipHeaderLength); - if( ntohs(udpHeader->source) > 1024 && ntohs(udpHeader->dest) > 1024 ) - { + if(ntohs(udpHeader->source) > 1024 && ntohs(udpHeader->dest) > 1024) { + bool detectedUsefulPacket = false; u_char* udpPayload = (u_char *)udpHeader + sizeof(UdpHeaderStruct); - MutexSentinel mutexSentinel(s_mutex); // serialize access for competing pcap threads + MutexSentinel mutexSentinel(s_mutex); // serialize access for competing pcap threads + + detectedUsefulPacket = TryIax2New(ethernetHeader, ipHeader, udpHeader, udpPayload); + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2Accept(ethernetHeader, ipHeader, udpHeader, + udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2Authreq(ethernetHeader, ipHeader, udpHeader, + udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2Hangup(ethernetHeader, ipHeader, udpHeader, + udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2ControlHangup(ethernetHeader, ipHeader, udpHeader, + udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2Reject(ethernetHeader, ipHeader, udpHeader, + udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2FullVoiceFrame(ethernetHeader, ipHeader, + udpHeader, udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2MetaTrunkFrame(ethernetHeader, ipHeader, + udpHeader, udpPayload); + } + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryIax2MiniVoiceFrame(ethernetHeader, ipHeader, + udpHeader, udpPayload); + } - bool detectedUsefulPacket = TryRtp(ethernetHeader, ipHeader, udpHeader, udpPayload); + if(!detectedUsefulPacket) { + detectedUsefulPacket = TryRtp(ethernetHeader, ipHeader, udpHeader, udpPayload); + } - if(!detectedUsefulPacket) - { - detectedUsefulPacket= TrySipInvite(ethernetHeader, ipHeader, udpHeader, udpPayload); + if(!detectedUsefulPacket) { + detectedUsefulPacket= TrySipInvite(ethernetHeader, ipHeader, udpHeader, + udpPayload); } - if(!detectedUsefulPacket) - { - detectedUsefulPacket = TrySipBye(ethernetHeader, ipHeader, udpHeader, udpPayload); + + if(!detectedUsefulPacket) { + detectedUsefulPacket = TrySipBye(ethernetHeader, ipHeader, udpHeader, + udpPayload); } } } @@ -711,6 +1525,7 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char MutexSentinel mutexSentinel(s_mutex); // serialize access for competing pcap threads s_lastHooveringTime = now; RtpSessionsSingleton::instance()->Hoover(now); + Iax2SessionsSingleton::instance()->Hoover(now); } } |