Сам себе IP-телефон. VoIP для программера
Салиев Александр aka Fagot
Xakep, номер #056, стр. 056-062-4
TCP-декодер
void tcpdecodeh323(char * data, int datalen)
{
H323SignalPDU H323pdu; /* Основной класс для всей сигнализации H.323, все подклассы наследуются от него */
PBYTEArray rawdata; /* Библиотека PwLib использует свои типы данных для работы с байтовыми массивами */
memcpy(rawdata.GetPointer(len-4),data+4,datalen-4); /* Сбросим уже ненужный 4-байтовый заголовок TPKT3 */
Q931 & q931pdu = H323pdu.GetQ931(); /* Захватим все, что относится к Q.931 */
if (!q931pdu.Decode(rawdata)) /* Попытаемся раскодировать */
{
cerr << "DecodeH323::Parse error of Q931 PDU" << endl; /* Однако, облом */
return;
}
/* Раскодировалось! Можно взять данные из Q.931 */
if (q931pdu.GetMessageType() == Q931::SetupMsg) /* Если это SETUP, то в нем есть номер вызываемого абонента и АОН */
{
......
Помимо других данных, тут есть и то, что интересует нас в первую очередь - АОН и номер вызываемого абонента:
Pstring telnum;
q931pdu.GetCallingPartyNumber(telnum);
cout << "\tAON = " << telnum << endl;
q931pdu.GetCalledPartyNumber(telnum);
cout << "\tAbonent Number = " << telnum << endl;
/*
Поковырявшись в файле q931.h, ты сможешь самостоятельно добыть все остальные данные из этого пакета.
*/
}
if (!q931pdu.HasIE(Q931::UserUserIE))
{
...
Если пакет Q.931 не содержит информационного элемента User-User, значит, это голый ISDN-пакет, без H.323-нагрузки.
...
}
else /* Попытаемся вытащить данные H.323 из IE:USER-USER */
{
PPER_Stream strm = q931pdu.GetIE(Q931::UserUserIE);
if (!H323pdu.Decode(strm))
{
...
Декодирования не получилось. Значит, в элементе User-User содержится не H.323-код, а нечто другое. Ну что ж, случается и такое...
...
}
cout << "H225\tReceived rawdata:\n" << hex << setfill('0') << setprecision(2) << rawdata << dec << setfill(' ') << endl;
cout << "H225\tReceived PDU:\n " << setprecision(2) << H323pdu << endl;
/* Здесь мы просто выводим содержимое пакета на экран, дабы не перегружать и без того уже объемный код, но пытливому читателю не составит труда самостоятельно выдрать нужные поля и использовать их в своих благородных целях */
}
}
UDP вариант я не привожу, т.к. он занимает много места. Если интересно, загляни на наш компакт-диск или скачай полные сорсы с www.xakep.ru. Там все очень подробно откомментировано.
И в заключение
Таким образом, мы создали снифер, который анализирует информацию H.323-VoIP-сессий, не прибегая ни к какому экзотическому железу, кроме нашей сетевой карточки. Безусловно, приведенный здесь пример, как и положено примеру, представляет собой обширное поле для доработки. Но основную свою миссию - разъяснить C++ программисту основы работы с данными протокола H.323, он выполнил. Неплохо бы приделать к нему буфер для фрагментированных TCP-пакетов, сделать несколько потоков для параллельного отслеживания нескольких сессий по их уникальным идентификаторам. Можно пойти и дальше, проанализировать сессию H.225, получив оттуда параметры для перехвата H.245, а оттуда уже получить IP-адреса и UDP-порты по которым идут непосредственно голосовые RTP-пакеты, отснифить их, произвести декодирование соответствующим кодеком и прослушать сам разговор. Можно устроить UDP-спуфинг заранее сформированными пакетами H225RAS (ведь с помощью рассмотренной библиотеки можно не только декодировать пакеты, но и формировать свои) и многое-многое другое. Но все это я оставляю для твоей творческой самореализации.