Mediastreamer2 VoIP 엔진 탐색. 7 부

글의 소재는 제 글에서 가져왔습니다. 젠 채널.

Mediastreamer2 VoIP 엔진 탐색. 7 부

TShark를 사용하여 RTP 패킷 분석

Mediastreamer2 VoIP 엔진 탐색. 7 부

과거에 기사 우리는 RTP 스트림을 사용하여 통신이 수행되는 톤 발생기와 톤 감지기에서 원격 제어 회로를 조립했습니다.

이 기사에서는 RTP 프로토콜을 사용한 오디오 신호 전송에 대해 계속 연구합니다. 먼저 테스트 애플리케이션을 송신기와 수신기로 나누고 네트워크 트래픽 분석기를 사용하여 RTP 스트림을 검사하는 방법을 알아보겠습니다.

따라서 어떤 프로그램 요소가 RTP 전송을 담당하고 어느 프로그램 요소가 수신을 담당하는지 더 명확하게 확인할 수 있도록 mstest6.c 파일을 송신기와 수신기에 대한 두 개의 독립적인 프로그램으로 나눕니다. 세 번째 파일에서 mstest_common.c, include 지시문을 사용하여 송신기와 수신기에 의해 연결됩니다.

/* Файл mstest_common.c Общие функции для передатчика и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>

define PCMU 0

/*---------------------------------------------------------*/
/* Функция регистрации типов полезных нагрузок. */
void register_payloads(void)
{  
 /* Регистрируем типы нагрузок в таблице профилей. Позднее, по индексу    взятому 
     из заголовка RTP-пакета из этой таблицы будут извлекаться    параметры 
     нагрузки, необходимые для декодирования данных пакета. */
  rtp_profile_set_payload (&av_profile, PCMU, &payload_type_pcm8000);
}

/*---------------------------------------------------------*/
/* Эта функция создана из функции create_duplex_rtpsession() в audiostream.c   медиастримера2. */
 static RtpSession *create_rtpsession (int loc_rtp_port, int loc_rtcp_port,  bool_t ipv6, RtpSessionMode mode)
{  
  RtpSession *rtpr;  rtpr = rtp_session_new ((int) mode);  
  rtp_session_set_scheduling_mode (rtpr, 0);  
  rtp_session_set_blocking_mode (rtpr, 0);
  rtp_session_enable_adaptive_jitter_compensation (rtpr, TRUE);
  rtp_session_set_symmetric_rtp (rtpr, TRUE); 
  rtp_session_set_local_addr (rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port,  loc_rtcp_port); 
  rtp_session_signal_connect (rtpr, "timestamp_jump",  (RtpCallback) rtp_session_resync, 0);
  rtp_session_signal_connect (rtpr, "ssrc_changed",  (RtpCallback) rtp_session_resync, 0);
  rtp_session_set_ssrc_changed_threshold (rtpr, 0);
  rtp_session_set_send_payload_type(rtpr, PCMU);

  /* По умолчанию выключаем RTCP-сессию, так как наш пульт не будет использовать 
  её. */  
 rtp_session_enable_rtcp (rtpr, FALSE);
 return rtpr;
}

이제 별도의 송신기 파일:

/* Файл mstest6.c Имитатор пульта управления (передатчика). */
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include "mstest_common.c"

/*----------------------------------------------------------*/
int main()
{ 
  ms_init();

/* Создаем экземпляры фильтров. */
  MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID); 
  MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);

/* Создаем фильтр кодера. */
  MSFilter *encoder = ms_filter_create_encoder("PCMU");

/* Регистрируем типы нагрузки. */
  register_payloads();

/* Создаем RTP-сессию передатчика. */
  RtpSession *tx_rtp_session = create_rtpsession (8010, 8011, FALSE, RTP_SESSION_SENDONLY);  
 rtp_session_set_remote_addr_and_port(tx_rtp_session,"127.0.0.1", 7010, 7011); 
 rtp_session_set_send_payload_type(tx_rtp_session, PCMU);  
 MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID); 
 ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, tx_rtp_session);

/* Создаем источник тактов - тикер. */ 
 MSTicker *ticker_tx = ms_ticker_new();

/* Соединяем фильтры передатчика. */ 
 ms_filter_link(voidsource, 0, dtmfgen, 0);  
 ms_filter_link(dtmfgen, 0, encoder, 0);
 ms_filter_link(encoder, 0, rtpsend, 0);

/* Подключаем источник тактов. */
  ms_ticker_attach(ticker_tx, voidsource);

/* Настраиваем структуру, управляющую выходным сигналом генератора. */ 
 MSDtmfGenCustomTone dtmf_cfg; 
 dtmf_cfg.tone_name[0] = 0; 
 dtmf_cfg.duration = 1000; 
 dtmf_cfg.frequencies[0] = 440;

/* Будем генерировать один тон, частоту второго тона установим в 0. */  
 dtmf_cfg.frequencies[1] = 0; 
 dtmf_cfg.amplitude = 1.0; 
 dtmf_cfg.interval = 0.;  
 dtmf_cfg.repeat_count = 0.;

/* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
* цикл и работу программы. */  
 char key='9'; 
 printf("Нажмите клавишу команды, затем ввод.n"  
"Для завершения программы введите 0.n");  
while(key != '0')  
{
 key = getchar();   
 if ((key >= 49) && (key <= 54)) 
   {
      printf("Отправлена команда: %cn", key);
      /* Устанавливаем частоту генератора в соответствии с
       * кодом нажатой клавиши. */
      dtmf_cfg.frequencies[0] = 440 + 100*(key-49);

      /* Включаем звуковой генератор c обновленной частотой. */
      ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,      (void*)&dtmf_cfg); 
   }
   /* Укладываем тред в спячку на 20мс, чтобы другие треды 
   * приложения получили время на работу. */ 
  ms_usleep(20000);
  }
}

마지막으로 수신자 파일은 다음과 같습니다.

/* Файл mstest7.c Имитатор приемника. */
include <mediastreamer2/mssndcard.h>
include <mediastreamer2/mstonedetector.h>
include <mediastreamer2/msrtp.h>

/* Подключаем заголовочный файл с функциями управления событиями  медиастримера.*/
include <mediastreamer2/mseventqueue.h>
/* Подключаем файл общих функций. */
include "mstest_common.c"

/* Функция обратного вызова, она будет вызвана фильтром, как только он   обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,MSToneDetectorEvent *ev)
{ 
 printf("Принята команда: %sn", ev->tone_name);
}

/*----------------------------------------------------------*/
int main()
{ 
 ms_init();

/* Создаем экземпляры фильтров. */  
 MSSndCard *card_playback =  ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); 
 MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback); 
 MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);

/* Очищаем массив находящийся внутри детектора тонов, он описывает
* особые приметы разыскиваемых сигналов.*/
  ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);

/* Подключаем к фильтру функцию обратного вызова. */  
ms_filter_set_notify_callback(detector,  (MSFilterNotifyFunc)tone_detected_cb, NULL);

/* Создаем массив, каждый элемент которого описывает характеристику
* одного из тонов, который требуется обнаруживать:
Текстовое имя
* данного элемента, частота в герцах, длительность в миллисекундах,
* минимальный уровень относительно 0,775В. */
  MSToneDetectorDef scan[6]= 
 {   
    {"V+",440, 100, 0.1}, /* Команда "Увеличить громкость". */
    {"V-",540, 100, 0.1}, /* Команда "Уменьшить громкость". */
    {"C+",640, 100, 0.1}, /* Команда "Увеличить номер канала". */
    {"C-",740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
    {"ON",840, 100, 0.1}, /* Команда "Включить телевизор". */
    {"OFF", 940, 100, 0.1}/* Команда "Выключить телевизор". */
  };

/* Передаем "приметы" сигналов детектор тонов. */
  int i; 
 for (i = 0; i < 6; i++) 
 { 
   ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,    &scan[i]); 
 }

/* Создаем фильтр декодера */
  MSFilter *decoder=ms_filter_create_decoder("PCMU");

/* Регистрируем типы нагрузки. */
  register_payloads();

/* Создаем RTP-сессию приемника. */
  MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
  RtpSession *rx_rtp_session = create_rtpsession (7010, 7011, FALSE, RTP_SESSION_RECVONLY);
  ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rx_rtp_session);

/* Создаем источник тактов - тикер. */ 
 MSTicker *ticker_rx = ms_ticker_new();

/* Соединяем фильтры приёмника. */
  ms_filter_link(rtprecv, 0, decoder, 0);
  ms_filter_link(decoder, 0, detector, 0);
  ms_filter_link(detector, 0, snd_card_write, 0);

/* Подключаем источник тактов. */
  ms_ticker_attach(ticker_rx, rtprecv);
  char key='9';
  printf( "Для завершения программы введите 0.n");
  while(key != '0') 
 {
    key = getchar();
   /* Укладываем тред в спячку на 20мс, чтобы другие треды    * приложения получили время на работу. */
   ms_usleep(20000); 
 }
}

송신기와 수신기를 컴파일한 다음 각각 자체 콘솔에서 실행합니다. 그런 다음 이전과 같이 작동해야 합니다. 송신기 콘솔에 1부터 6까지의 숫자만 입력하면 그에 대한 응답이 수신기 콘솔에 나타나야 합니다. 스피커에서 신호음이 들려야 합니다. 모든 것이 그렇다면 수신기와 송신기 사이에 연결이 설정된 것입니다. 송신기에서 수신기로 RTP 패킷이 지속적으로 전송됩니다.

이제 트래픽 분석기를 설치할 때입니다. 이를 위해 우수한 Wireshark 프로그램(TShark라고 함)의 콘솔 버전을 설치합니다. 나는 프로그램 관리에 대한 설명을 용이하게 하기 위해 추가 논의를 위해 TShark를 선택했습니다. Wireshark를 사용하려면 엄청난 양의 스크린샷이 필요합니다. 이는 Wireshark의 새 버전이 출시되면 금방 구식이 될 수 있습니다.

Wireshark 사용 방법을 알고 있다면 이를 사용하여 예제를 연구할 수 있습니다. 하지만 이 경우에도 VoIP 애플리케이션 테스트를 자동화하고 원격 캡처를 수행하는 데 도움이 되므로 TShark를 마스터하는 것이 좋습니다.

다음 명령을 사용하여 TShark를 설치합니다.

$ sudo apt-get install tshark

전통적으로 우리는 프로그램 버전을 요청하여 설치 결과를 확인합니다.

$ tshark --version

적절한 답변을 받으면 계속 진행합니다.

현재 우리의 패킷은 컴퓨터 내부로만 들어가므로 tshark에게 그러한 패킷만 표시하도록 지시할 수 있습니다. 이렇게 하려면 인터페이스에서 패킷 캡처를 선택해야 합니다. 루프백 (루프백) TShark에 옵션을 전달하여 -일로:

$ sudo tshark -i lo

송신기에서 보낸 패킷에 대한 메시지는 즉시 콘솔에 쏟아지기 시작합니다(리모컨의 버튼을 눌렀는지 여부에 관계없이 계속해서). 아마도 귀하의 컴퓨터에는 로컬 루프를 통해 패킷을 보내는 프로그램이 있을 수 있으며, 이 경우 우리는 우리 패킷과 다른 사람의 패킷을 혼합하여 받게 됩니다. 리모콘에서 보낸 패킷만 목록에 표시되도록 포트 번호별로 필터를 추가합니다. Ctrl-C를 눌러 분석기를 중지하고 리모콘이 전송 대상 포트(8010)로 사용하는 포트 번호에 대한 필터를 입력합니다. -f "udp 포트 8010". 이제 명령줄은 다음과 같습니다.

$ sudo tshark -i lo -f "udp port 8010"

다음 출력이 콘솔에 나타납니다(처음 10줄).

 1 0.000000000    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 2 0.020059705    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 3 0.040044409    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 4 0.060057104    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 5 0.080082311    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172  
 6 0.100597153    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 7 0.120122668    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 8 0.140204789    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 9 0.160719008    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
10 0.180673685    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172

현재로서는 이는 패킷이 아니라 번호가 매겨진 이벤트 목록입니다. 여기서 각 줄은 인터페이스에서 발견된 다음 패킷에 대한 메시지입니다. 우리는 이미 패킷 필터링을 처리했으므로 목록에는 송신기에서 보낸 패킷에 대한 메시지만 표시됩니다. 다음으로 이 테이블을 열 번호로 해독해 보겠습니다.

이벤트 번호.
발생 시간.
패킷의 소스 IP 주소와 패킷의 대상 IP 주소입니다.
RTP 패킷은 UDP 패킷 내부의 페이로드로 전송되므로 패킷의 프로토콜은 UDP로 표시됩니다.
패킷 크기(바이트)입니다.
패킷의 소스 포트 번호와 패킷의 대상 포트 번호입니다.
패킷 페이로드의 크기를 보면 송신기가 172바이트 크기의 RTP 패킷을 생성한다는 결론을 내릴 수 있습니다. 이 패킷은 가슴 안의 오리처럼 214바이트 크기의 UDP 패킷 내부에 있습니다.
이제 UDP 패킷 내부를 살펴볼 시간입니다. 이를 위해 확장된 키 세트를 사용하여 TShark를 시작합니다.

sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x

결과적으로 프로그램 출력이 강화됩니다. 이를 유발한 패키지의 내부 콘텐츠에 대한 암호 해독이 각 이벤트에 추가됩니다. 출력을 더 잘 보려면 Ctrl-C를 눌러 TShark를 중지하거나 파일 이름 tee <filename>을 지정하고 tee 프로그램에 대한 파이프라인을 실행 명령에 추가하여 출력을 파일에 복제할 수 있습니다.

$ sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x | tee  log.txt

이제 파일에서 얻은 내용을 살펴보겠습니다. 여기에 첫 번째 패키지가 있습니다.

1 0.000000000    127.0.0.1 → 127.0.0.1    RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6B8B4567, Seq=58366, Time=355368720
Frame 1: 214 bytes on wire (1712 bits), 214 bytes captured (1712 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1User Datagram Protocol, Src Port: 8010, Dst Port: 7010
Real-Time Transport Protocol    [Stream setup by HEUR RT (frame 1)]
        [Setup frame: 1] 
       [Setup Method: HEUR RT]
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0   
   0... .... = Marker: False
    Payload type: ITU-T G.711 PCMU (0)
    Sequence number: 58366    [Extended sequence number: 58366]
    Timestamp: 355368720
    Synchronization Source identifier: 0x6b8b4567 (1804289383)
    Payload: ffffffffffffffffffffffffffffffffffffffffffffffff...

0000  00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.
0010  00 c8 3c 69 40 00 40 11 ff b9 7f 00 00 01 7f 00   ..<i@.@.........
0020  00 01 1f 4a 1b 62 00 b4 fe c7 80 00 e3 fe 15 2e   ...J.b..........
0030  7f 10 6b 8b 45 67 ff ff ff ff ff ff ff ff ff ff   ..k.Eg..........
0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0080  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0090  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00a0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00b0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00c0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00d0  ff ff ff ff ff ff                                  ......

우리는 다음 기사에서 이 목록에 포함된 정보를 분석하는 데 전념할 것이며 필연적으로 RTP 패키지의 내부 구조에 대해 이야기할 것입니다.

출처 : habr.com

코멘트를 추가