Сам себе 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 (ведь с помощью рассмотренной библиотеки можно не только декодировать пакеты, но и формировать свои) и многое-многое другое. Но все это я оставляю для твоей творческой самореализации.

Назад на стр. 056-062-3  Содержание  Вперед на стр. 056-062-5