Upload
giovanni-attolini
View
25
Download
0
Embed Size (px)
Citation preview
UNIVERSIDADE DE CAXIAS DO SUL - UCS
CAMPUS UNIVERSITÁRIO DA REGIÃO DOS VINHEDOS - CARVI
CENTRO DE CIÊNCIAS EXATAS DA NATUREZA E DE TECNOLOGIA - CENT
ENGENHARIA ELÉTRICA
GIOVANNI AUGUSTO ATTOLINI
DESENVOLVIMENTO DE ANALISADOR E MODIFICADOR DE
PACOTES PARA DETECÇÃO E CORREÇÃO DE PROBLEMAS DE
INTEROPERABILIDADE DO SIP ENTRE DISPOSITIVOS
BENTO GONÇALVES
2011
GIOVANNI AUGUSTO ATTOLINI
DESENVOLVIMENTO DE ANALISADOR E MODIFICADOR DE
PACOTES PARA DETECÇÃO E CORREÇÃO DE PROBLEMAS DE
INTEROPERABILIDADE DO SIP ENTRE DISPOSITIVOS
Trabalho de conclusão do curso de graduação
em Engenharia Elétrica apresentado ao Centro
de Ciências Exatas da Natureza e de
Tecnologia, como requisito para obtenção do
título de Engenheiro Eletricista.
Orientador: Prof. Me. Ricardo Balbinot
BENTO GONÇALVES
2011
GIOVANNI AUGUSTO ATTOLINI
DESENVOLVIMENTO DE ANALISADOR E MODIFICADOR DE
PACOTES PARA DETECÇÃO E CORREÇÃO DE PROBLEMAS DE
INTEROPERABILIDADE DO SIP ENTRE DISPOSITIVOS
Trabalho de conclusão do curso de graduação
em Engenharia Elétrica apresentado ao Centro
de Ciências Exatas da Natureza e de
Tecnologia, como requisito para obtenção do
título de Engenheiro Eletricista.
Aprovado em _____ de _________________ de _________.
BANCA EXAMINADORA:
Profa. Me. Marilda Spindola - UCS
________________________________
Prof. Me. Ricardo Becker - UCS
________________________________
Prof. Me. Ricardo Balbinot - UCS
________________________________
AGRADECIMENTOS
Aos professores do curso de Engenharia Elétrica da Universidade de Caxias do Sul
cuja meta de qualidade no ensino foi sempre superar as expectativas.
Ao professor Ricardo Balbinot em especial pela ajuda no desenvolvimento deste
projeto.
A minha família pelo apoio incondicional.
A minha noiva Mariele pela compreensão, confiança e amor.
A empresa Simar Telecom pela infraestrutura cedida para os testes.
Enfim, a todos que de alguma forma participaram desta etapa da minha vida.
“The show must go on!”
Freddie Mercury
RESUMO
Historicamente o homem tem produzido equipamentos buscando a evolução e
facilitação da comunicação. A Voz Sobre IP (VoIP) é um dos serviços que nasceu dessa
evolução. Este serviço utiliza uma rede comutada por pacotes para a transmissão de voz. Para
que seja possível o estabelecimento de uma chamada VoIP, é necessário o uso de um
protocolo de sinalização chamado SIP ou “Session Initiation Protocol”. O sucesso no
estabelecimento depende da correta operação desse protocolo através da rede de dados.
Existem diversas falhas que podem ocorrer durante a configuração e a operação desse
protocolo. Portanto, observou-se a necessidade do desenvolvimento de uma ferramenta capaz
de criar um registro dos eventos para a análise e que possibilite também a alteração da
sinalização sem mesmo alterar qualquer configuração nos equipamentos envolvidos na
comunicação. Para que isso seja possível, é utilizada uma biblioteca junto com uma
linguagem de programação para efetuar a captura, análise e alteração desses pacotes que
fazem parte da sinalização. Detectado o problema, a alteração correta na configuração dos
equipamentos envolvidos será feita reduzindo assim o tempo de implantação.
Palavras-chave: Voice over IP, rede, pacotes, protocolo, sinalização, captura, injeção.
ABSTRACT
Historically, devices were produced always looking for the evolution of
communication. The Voice over IP (VoIP) is one service that came from this evolution. This
service uses a packet switching network to voice transmission. A protocol named SIP or
"Session Initiation Protocol" is used for VoIP calls signaling management. The establishment
success‟s depends on the correct SIP configuration and operation, but there are a lot of
problems that can appear during this proccess. Therefore, a development of a SIP analyzer
tool was observed. With this tool, the operator must be able to change the signaling between
the devices without any device configuration changing. A library with a programming
language is used to create a tool able to capture, change and inject the signaling packets. After
the fail detection, the correct changing in device configuration is made reducing the
implantation time.
Keywords: Voice over IP, network, packets, protocol, signaling, capture, injection.
LISTA DE ILUSTRAÇÕES
Figura 1 - Comunicação baseada em comutação de circuitos. ............................................... 24
Figura 2 - Comunicação baseada na comutação de pacotes. .................................................. 26
Figura 3 - Modelo de referência OSI. ................................................................................... 29
Figura 4 - Modelo de referência TCP/IP. .............................................................................. 30
Figura 5 - Campos do pacote IP. .......................................................................................... 31
Figura 6 – Cabeçalho UDP. .................................................................................................. 33
Figura 7 - Campos utilizados para o cálculo do checksum UDP. ........................................... 34
Figura 8 - Protocolos no modelo TCP/IP. ............................................................................. 35
Figura 9 - Cabeçalho RTP. ................................................................................................... 37
Figura 10 - Exemplo de requisição SIP. ............................................................................... 40
Figura 11 - Exemplo de linha de requisição. ......................................................................... 40
Figura 12 - Método INVITE. ............................................................................................... 41
Figura 13 - Método ACK. .................................................................................................... 42
Figura 14 - Método CANCEL. ............................................................................................. 43
Figura 15 - Método BYE. ..................................................................................................... 45
Figura 16 - Método REGISTER. .......................................................................................... 46
Figura 17 - Exemplo de resposta SIP. ................................................................................... 47
Figura 18 - Exemplo de linha de estado. ............................................................................... 48
Figura 19 - Exemplo do campo From retirado de uma requisição SIP. .................................. 50
Figura 20 - Exemplo do campo To retirado de uma requisição SIP. ...................................... 50
Figura 21 - Exemplo do campo Via retirado de uma requisição SIP. .................................... 51
Figura 22 - Exemplo do campo Call-ID retirado de uma requisição SIP. .............................. 51
Figura 23 - Exemplo do campo CSeq retirado de uma requisição SIP. .................................. 52
Figura 24 - Exemplo do campo Contact retirado de uma requisição SIP. .............................. 52
Figura 25 - Exemplo do campo Max-Forwards retirado de uma requisição SIP. ................... 53
Figura 26 - Exemplo do campo WWW-Authenticate retirado de uma requisição SIP. ............ 53
Figura 27 - Exemplo do campo Authorization retirado de uma requisição SIP. ..................... 54
Figura 28 - Geração da primeira criptografia. ....................................................................... 55
Figura 29 - Geração da segunda criptografia. ....................................................................... 55
Figura 30 - Geração da terceira criptografia. ........................................................................ 56
Figura 31 - Exemplo de criptografia com dados reais. .......................................................... 56
Figura 32 - Código para criação de uma sessão de captura. .................................................. 59
Figura 33 - Compilação de um filtro de captura. ................................................................... 59
Figura 34 Aplicação de um filtro de captura em uma interface. ........................................... 60
Figura 35 - Exemplo de expressão de filtro. ......................................................................... 60
Figura 36 - Exemplo de código utilizando libpcap. .............................................................. 61
Figura 37 - Visão geral do Eclipse........................................................................................ 64
Figura 38 - Visão geral do Wireshark. .................................................................................. 64
Figura 39 - Visão geral do eyeBeam. .................................................................................... 65
Figura 40 - Detalhes da configuração do eyeBeam................................................................ 66
Figura 41 - Configuração do Asterisk. .................................................................................. 67
Figura 42 - Configuração do plano de numeração no Asterisk. ............................................. 67
Figura 43 - Visão geral do menu principal. ........................................................................... 69
Figura 44 - Visão geral da seção "Escuta". ........................................................................... 70
Figura 45 - Visão geral da sessão de captura. ....................................................................... 71
Figura 46 - Visão geral da seção "Dados Escutados". ........................................................... 71
Figura 47 - Visão geral da seção "Injeção". .......................................................................... 72
Figura 48 - Visão geral da opção de "Mostrar Resultados". .................................................. 73
Figura 49 - Visão geral da seção "Limpar Resultados". ........................................................ 74
Figura 50 - Visão geral da seção "Limpar Tudo". ................................................................. 74
Figura 51 – Fluxograma geral do projeto. ............................................................................. 75
Figura 52 - Exemplo de impressão realizada pela função imprime_pkt. ................................ 96
Figura 53 - Topologia utilizada na validação da ferramenta desenvolvida. ......................... 126
Figura 54 - Seção "Dados Escutados". ................................................................................ 130
Figura 55 - Pacotes capturados pelo Wireshark. ................................................................. 130
Figura 56 - Pacote 01 capturado pelo Wireshark. ............................................................... 131
Figura 57 - Seção "Dados Escutados". ................................................................................ 132
Figura 58 - Seção "Injeção". ............................................................................................... 133
Figura 59 - Seção "Mostrar Resultados". ............................................................................ 133
Figura 60 - Pacotes capturados pelo Wireshark. ................................................................. 134
Figura 61 - Pacote 02 capturado pelo Wireshark. ............................................................... 135
TABELAS
Tabela 1 - Comparação entre a rede comutada por circuitos e a rede comutada por pacotes. . 27
Tabela 2 - Lista de codecs comumente utilizados. ................................................................ 38
Tabela 3 – Campos no cabeçalho de uso obrigatório no método INVITE. ............................ 41
Tabela 4 - Campos no cabeçalho de uso obrigatório no método ACK. .................................. 43
Tabela 5 - Campos no cabeçalho de uso obrigatório no método CANCEL. .......................... 44
Tabela 6 - Campos no cabeçalho de uso obrigatório no método BYE. .................................. 45
Tabela 7 - Campos no cabeçalho de uso obrigatório no método REGISTER. ....................... 46
Tabela 8 - Campos no cabeçalho de uso obrigatório no método OPTIONS........................... 47
Tabela 9 - Classes das mensagens de resposta SIP. ............................................................... 48
Tabela 10 - Mensagens SIP. ................................................................................................. 48
Tabela 11 - Exemplo de arquivo de captura. ......................................................................... 79
Tabela 12 - Exemplo de arquivo de informação da sessão. ................................................... 82
Tabela 13 - Exemplo de arquivo de informações dos campos SIP......................................... 82
Tabela 14 - Arquivo de cabeçalho config.h. .......................................................................... 85
Tabela 15 - Estrutura do cabeçalho Ethernet. ........................................................................ 88
Tabela 16 - Estrutura do cabeçalho IP. ................................................................................. 88
Tabela 17 - Estrutura do cabeçalho UDP. ............................................................................. 89
Tabela 18 - Estrutura do pseudo-header. .............................................................................. 89
Tabela 19 - Desenvolvimento da função valor_string. .......................................................... 90
Tabela 20 - Desenvolvimento da função troca_string. .......................................................... 91
Tabela 21 - Desenvolvimento da função metodo_sip. ........................................................... 92
Tabela 22 - Desenvolvimento da função valor_sip_string. ................................................... 93
Tabela 23 - Desenvolvimento da função payload_sip. .......................................................... 93
Tabela 24 - Parte do desenvolvimento da função str2hex...................................................... 94
Tabela 25 - Desenvolvimento da função imprime_pkt. ......................................................... 95
Tabela 26 - Desenvolvimento da função rl_ttyset. ................................................................ 96
Tabela 27 - Início da função callback. .................................................................................. 97
Tabela 28 - Primeira parte do desenvolvimento da função callback. ..................................... 98
Tabela 29 – Segunda parte do desenvolvimento da função callback. .................................... 98
Tabela 30 - Terceira parte do desenvolvimento da função callback. ..................................... 99
Tabela 31 - Desenvolvimento da função cabecalho. ........................................................... 100
Tabela 32 - Desenvolvimento da função menu_main. ......................................................... 101
Tabela 33 - Desenvolvimento da função menu_1................................................................ 101
Tabela 34 - Desenvolvimento da função menu_1_1. ........................................................... 102
Tabela 35 - Desenvolvimento da função menu_1_2. ........................................................... 103
Tabela 36 - Desenvolvimento da função menu_1_3. ........................................................... 103
Tabela 37 - Desenvolvimento da função menu_2................................................................ 104
Tabela 38 - Desenvolvimento da função menu_3................................................................ 105
Tabela 39 - Desenvolvimento da função menu_4................................................................ 106
Tabela 40 - Desenvolvimento da função menu_5................................................................ 106
Tabela 41 - Desenvolvimento da função menu_6................................................................ 107
Tabela 42 - Inicialização das variáveis globais. .................................................................. 108
Tabela 43 - Carregamento dos valores salvos. .................................................................... 109
Tabela 44 - Verificação do diretório de armazenamento. .................................................... 109
Tabela 45 - Desenvolvimento do controle de acesso principal. ........................................... 109
Tabela 46 - Desenvolvimento do controle de acesso da seção "Escuta". ............................. 111
Tabela 47 - Desenvolvimento da função de captura da seção "Escuta". .............................. 112
Tabela 48 - Desenvolvimento das threads de controle da seção "Escuta". .......................... 113
Tabela 49 - Controle de menu da seção "Dados Escutados". ............................................... 114
Tabela 50 - Parte inicial da função dados_esc. ................................................................... 115
Tabela 51 - Gravação dos campos SIP no arquivo. ............................................................. 115
Tabela 52 - Impressão do menu de acesso aos campos SIP. ................................................ 116
Tabela 53 - Controle interface operador seção "Injeção". ................................................... 117
Tabela 54 - Desenvolvimento das threads de controle de injeção e captura. ....................... 117
Tabela 55 - Declaração das variáveis na função injeta. ....................................................... 118
Tabela 56 - Alocação de memória das variáveis. ................................................................ 119
Tabela 57 - Início do processo de injeção e captura. ........................................................... 120
Tabela 58 - Autenticação do SIP. ....................................................................................... 121
Tabela 59 - Leitura dos dados do cabeçalho Ethernet. ........................................................ 122
Tabela 60 - Leitura dos dados e criação dos cabeçalhos IP e UDP. ..................................... 122
Tabela 61 - Geração dos checksums IP e UDP. ................................................................... 123
Tabela 62 - Impressão do pacote e injeção. ........................................................................ 123
Tabela 63 - Desenvolvimento da função func_escuta. ........................................................ 124
Tabela 64 - Desenvolvimento das threads de captura. ........................................................ 125
Tabela 65 - Pacote 01 capturado pelo software desenvolvido. ............................................ 130
Tabela 66 - Pacote 02 capturado pelo software. .................................................................. 134
Tabela 67 - Código para geração do checksum. .................................................................. 141
Tabela 68 - Código utilizado para a geração do hash MD5. ................................................ 142
Tabela 69 - Código para organização dos bits na criação do pacote. ................................... 148
SUMÁRIO
1 INTRODUÇÃO ............................................................................................... 19
1.1 RELEVÂNCIA E JUSTIFICATIVA ................................................................. 20
1.2 MOTIVAÇÃO PARA O DESENVOLVIMENTO ............................................. 20
1.3 OBJETIVOS GERAIS ....................................................................................... 21
1.4 OBJETIVOS ESPECÍFICOS ............................................................................. 21
1.5 LIMITAÇÃO DO ESCOPO .............................................................................. 22
1.6 ORGANIZAÇÃO DO TRABALHO ................................................................. 22
2 REVISÃO BIBLIOGRÁFICA ........................................................................ 23
2.1 COMUTAÇÃO DE CIRCUITOS ...................................................................... 23
2.2 COMUTAÇÃO DE PACOTES ......................................................................... 24
2.2.1 Pacotes .............................................................................................................. 25
2.3 COMPARAÇÃO ENTRE COMUTAÇÃO DE CIRCUITOS E COMUTAÇÃO
DE PACOTES ..................................................................................................................... 26
2.4 MODELOS DE REFERÊNCIA ......................................................................... 28
2.4.1 Modelo OSI ...................................................................................................... 28
2.4.2 Modelo TCP/IP ................................................................................................ 30
2.4.2.1 Camada de Inter-redes ....................................................................................... 31
2.4.2.1.1 Checksum IP ..................................................................................................... 32
2.4.2.2 Camada de Transporte ....................................................................................... 33
2.4.2.2.1 Checksum UDP ................................................................................................. 34
2.4.2.3 Camada de Aplicação ........................................................................................ 35
2.4.2.4 Camada de Infraestrutura de Rede ...................................................................... 35
2.5 VOZ SOBRE IP ................................................................................................ 36
2.5.1 RTP .................................................................................................................. 36
2.5.2 SIP .................................................................................................................... 38
2.5.2.1 Entidades SIP .................................................................................................... 39
2.5.2.2 Requisições SIP ................................................................................................. 39
2.5.2.2.1 Método INVITE ................................................................................................ 40
2.5.2.2.2 Método ACK ..................................................................................................... 42
2.5.2.2.3 Método CANCEL .............................................................................................. 43
2.5.2.2.4 Método BYE ...................................................................................................... 44
2.5.2.2.5 Método REGISTER .......................................................................................... 45
2.5.2.2.6 Método OPTIONS............................................................................................. 46
2.5.2.3 Respostas SIP .................................................................................................... 47
2.5.2.4 Campos do Cabeçalho ....................................................................................... 49
2.5.2.4.1 From ................................................................................................................. 50
2.5.2.4.2 To ...................................................................................................................... 50
2.5.2.4.3 Via ..................................................................................................................... 51
2.5.2.4.4 Call-ID .............................................................................................................. 51
2.5.2.4.5 CSeq .................................................................................................................. 52
2.5.2.4.6 Contact .............................................................................................................. 52
2.5.2.4.7 Max-Forwards .................................................................................................. 52
2.5.2.4.8 WWW-Authenticate .......................................................................................... 53
2.5.2.4.9 Authorization .................................................................................................... 53
2.5.2.5 Autenticação do SIP .......................................................................................... 54
2.5.2.6 Vulnerabilidades do SIP .................................................................................... 56
2.6 BIBLIOTECA LIBPCAP .................................................................................. 57
2.6.1 Captura de Pacotes Utilizando a LIBPCAP ................................................... 58
2.6.2 Filtros de Captura Utilizados com a LIBPCAP .............................................. 59
2.6.3 Exemplo de Código .......................................................................................... 60
3 IMPLEMENTAÇÃO DO PROTÓTIPO ........................................................ 62
3.1 METODOLOGIA .............................................................................................. 62
3.2 FERRAMENTAS UTILIZADAS ...................................................................... 62
3.2.1 Eclipse IDE for C/C++ Developers ................................................................... 63
3.2.2 Wireshark Network Protocol Analyzer.............................................................. 63
3.2.3 eyeBeam ............................................................................................................ 65
3.2.4 Asterisk ............................................................................................................. 66
3.3 ELABORAÇÃO DO FLUXOGRAMA ............................................................. 68
3.3.1 Análises Possíveis Através da Ferramenta...................................................... 68
3.3.2 Principais Funções do Analisador ................................................................... 68
3.3.3 Organização da Interface com o Operador .................................................... 69
3.3.3.1 Seção “Escuta” .................................................................................................. 70
3.3.3.2 Seção “Dados Escutados” .................................................................................. 70
3.3.3.3 Seção “Injeção” ................................................................................................. 72
3.3.3.4 Seção “Mostrar Resultados”............................................................................... 72
3.3.3.5 Seção “Limpar Resultados” ............................................................................... 73
3.3.3.6 Seção “Limpar Tudo” ........................................................................................ 74
3.3.4 Fluxograma ...................................................................................................... 75
3.3.4.1 Determinação do Filtro de Captura .................................................................... 77
3.3.4.2 Determinação dos Campos para Alteração ......................................................... 77
3.4 DESENVOLVIMENTO DO ANALISADOR PROPOSTO ............................... 78
3.4.1 Definições Iniciais ............................................................................................ 78
3.4.2 Padrões de Arquivos Utilizados ...................................................................... 78
3.4.2.1 Arquivos de Captura .......................................................................................... 79
3.4.2.2 Arquivo de Informações da Sessão .................................................................... 81
3.4.2.3 Arquivo de Informações dos Campos SIP .......................................................... 82
3.4.3 Estrutura do Código ........................................................................................ 83
3.4.4 Declaração das Bibliotecas e Variáveis Globais.............................................. 85
3.4.5 Estruturas de Cabeçalho ................................................................................. 88
3.4.6 Funções Globais ............................................................................................... 89
3.4.6.1 Função valor_string ........................................................................................... 89
3.4.6.2 Função troca_string ........................................................................................... 90
3.4.6.3 Função metodo_sip ............................................................................................ 92
3.4.6.4 Função valor_sip_string ..................................................................................... 92
3.4.6.5 Função payload_sip ........................................................................................... 93
3.4.6.6 Função str2hex .................................................................................................. 94
3.4.6.7 Função imprime_pkt .......................................................................................... 95
3.4.6.8 Função rl_ttyset ................................................................................................. 96
3.4.6.9 Função callback ................................................................................................. 97
3.4.7 Controle de Menu .......................................................................................... 100
3.4.7.1 Função cabecalho ............................................................................................ 100
3.4.7.2 Função menu_main .......................................................................................... 100
3.4.7.3 Função menu_1 ............................................................................................... 101
3.4.7.4 Função menu_1_1 ............................................................................................ 102
3.4.7.5 Função menu_1_2 ............................................................................................ 103
3.4.7.6 Função menu_1_3 ............................................................................................ 103
3.4.7.7 Função menu_2 ............................................................................................... 104
3.4.7.8 Função menu_3 ............................................................................................... 105
3.4.7.9 Função menu_4 ............................................................................................... 105
3.4.7.10 Função menu_5 ............................................................................................... 106
3.4.7.11 Função menu_6 ............................................................................................... 107
3.4.8 Controle Principal ......................................................................................... 107
3.4.9 Controle de Escuta ......................................................................................... 111
3.4.10 Controle de Alteração .................................................................................... 114
3.4.11 Controle de Injeção ........................................................................................ 116
4 VALIDAÇÃO DA FERRAMENTA ............................................................. 126
4.1 TOPOLOGIA UTILIZADA NA VALIDAÇÃO .............................................. 126
4.2 OBJETIVOS EM CADA TESTE .................................................................... 127
4.2.1 Teste de Validação de Captura ..................................................................... 127
4.2.2 Teste de Validação de Captura e Injeção ...................................................... 127
5 RESULTADOS E CONCLUSÕES ............................................................... 129
5.1 RESULTADOS OBTIDOS DO TESTE DE CAPTURA ................................. 129
5.2 RESULTADOS OBTIDOS DO TESTE DE CAPTURA E INJEÇÃO ............. 132
5.3 CONCLUSÃO ................................................................................................. 136
5.4 SUGESTÃO PARA TRABALHOS FUTUROS .............................................. 137
5.4.1 Aperfeiçoamento da Ferramenta .................................................................. 137
5.4.2 Continuidade da Proposta ............................................................................. 137
REFERÊNCIAS BIBLIOGRÁFICAS ............................................................................ 139
ANEXO A – Código para geração do Checksum utilizado nos cabeçalhos IP e UDP ... 141
ANEXO B – Código para geração do hash MD5 utilizado no SIP ................................. 142
ANEXO C – Código para organização dos bits na criação do pacote ............................ 148
SIGLAS
ADPCM: Adaptive Differential Pulse Code Modulation
ARPANET: Advanced Research Projects Agency Network
CDR: Call Retail Records
DoD: Department of Defense
DSP: Digital Signal Processor
FTP: File Transfer Protocol
HTTP: Hyper Text Transfer Protocol
IEEE: Institute of Electrical and Electronics Engineers
IP: Internet Protocol
IPDR: IP Detail Record
ISO: International Organization for Standardization
ITU-T: International Telecommunication Union
MD5: Message-Digest Algorithm 5
MOS: Mean Opinion Score
MPEG: Moving Picture Experts Group
NAT: Network Address Translation
OSI: Open Systems Interconnection
PBX: Private Branch Exchange
PC: Personal Computer
PCM: Pulse Code Modulation
QoS: Quality of Service
RTP: Real-time Transport Protocol
SDP: Session Description Protocol
SIP: Session Initiation Protocol
SMTP: Simple Mail Transfer Protocol
TCP: Transmission Control Protocol
ToS: Type of Service
TTL: Time To Live
UA: User Agent
UDP: User Datagram Protocol
URI: Uniform Resource Identifier
VoIP: Voice Over IP
VPN: Virtual Private Network
19
1 INTRODUÇÃO
É de amplo conhecimento a importância da invenção do telefone na evolução dos
sistemas de comunicação, pois foi a partir dele que a comunicação à distância tornou-se mais
simples e efetiva, fazendo com que notícias que antes levavam tempo para serem entregues
passassem a ser transmitidas em um período mais curto de tempo (WALLINGFORD, 2005).
Depois do telefone, a comunicação à distância evoluiu para a comunicação de dados, dando
origem posteriormente a rede mundial de computadores, hoje conhecida como Internet. A
Internet hoje possibilita a comunicação à distância de diversas formas e a transmissão de
dados em diversos formatos, sejam eles imagens, vídeos, músicas ou documentos. A Internet
nasceu de uma concepção de rede baseada na comutação de pacotes onde o meio é
compartilhado (GOLENIEWSKI, 2006).
A comunicação por voz, antes normalmente feita utilizando o telefone, hoje pode
também ser feita pela Internet. Criou-se um serviço específico que trata da comunicação de
voz sobre a Internet, denominado Voz Sobre IP ou VoIP (Voice over IP), onde os dados
transmitidos possuem informações de fala que saem de uma origem e chegam a um destino
(WALLINGFORD, 2005). Para o seu funcionamento, a VoIP conta com o auxílio de alguns
protocolos, entre os quais podem ser destacados o RTP (Realtime Transfer Protocol) e o SIP
(Session Initiation Protocol). O primeiro é responsável pelo transporte de dados em tempo
real, no caso da VoIP, a voz digitalizada, e o segundo é responsável pelo estabelecimento das
sessões multimídia, no caso as chamadas usando a rede IP (CAMARILLO, 2002).
O protocolo SIP, por ser um protocolo relativamente novo e ainda em franco
desenvolvimento, apresenta incompatibilidades entre implementações, vulnerabilidades de
segurança e até mesmo eventuais brechas de operação que podem dificultar sua utilização
(CAMARILLO, 2002). Dados esses possíveis problemas de operação do SIP, em conjunto
com a necessidade de redução do tempo de instalação de uma solução de VoIP, o presente
trabalho trata do desenvolvimento de uma ferramenta capaz de capturar, alterar e injetar os
pacotes referentes a sinalização da VoIP a fim de fornecer uma análise da interoperabilidade
do protocolo SIP entre os dispositivos para o operador da ferramenta.
20
1.1 RELEVÂNCIA E JUSTIFICATIVA
Face aos fatos destacados anteriormente, em algumas implementações da tecnologia
de VoIP ocorrem dificuldades em obter a interoperabilidade entre dispositivos distintos
através do uso do protocolo SIP. Como exemplo, em algumas situações, senão a maioria
delas, apenas no envio da mensagem SIP na qual o usuário a ser contatado é informado, já se
observam problemas na comunicação. Nota-se, portanto, que com o uso de uma ferramenta
que possibilite a análise dessa troca de informações entre esses dispositivos, e em um segundo
passo, permita a alteração dessas informações de forma a corrigir a anomalia detectada, torna-
se possível a redução no tempo de análise e solução dos problemas reduzindo ao final o tempo
total de implantação.
A solução proposta também se diferencia de softwares analisadores de protocolos
como o Wireshark (LAMPING, SHARPE e WARNICKE, 2011), pelo fato de conceber
também a alteração de campos do protocolo e posterior injeção do mesmo na rede para fins de
testes.
1.2 MOTIVAÇÃO PARA O DESENVOLVIMENTO
A motivação para o desenvolvimento deste projeto surgiu da observação feita em
campo durante a implantação de um dispositivo SIP interligado a um servidor SIP. No caso
específico desta implantação, o dispositivo SIP em questão possui algumas limitações quanto
a facilidade de configuração. Em alguns casos, muito tempo é demandado para corrigir a
configuração do dispositivo adequando as informações de identificação do usuário,
autenticação do usuário e identificação do usuário que está sendo convidado para uma sessão
multimídia. Com base nestas dificuldades, definiu-se como uma forma de minimizar o tempo
de implantação, criar uma ferramenta que pudesse fornecer análises acerca da
interoperabilidade do protocolo SIP entre o dispositivo em questão e o servidor SIP. A
ferramenta deve ser capaz de capturar pacotes da rede, alterar esses pacotes e injetar esses
pacotes para gerar uma nova análise. Sendo as alterações efetuadas nos pacotes SIP mais
simples do que a configuração no próprio dispositivo SIP, ocorre uma minimização no tempo
21
de implantação além de não depender muitas vezes do fabricante para detectar possíveis
problemas existentes na implementação do protocolo SIP dentro do equipamento.
1.3 OBJETIVOS GERAIS
O trabalho apresenta como tema o desenvolvimento de um software baseado no
sistema operacional Linux para efetuar a análise e a possível correção no fluxo de mensagens
SIP durante a negociação de uma chamada via VoIP. Esse software está baseado na captura,
alteração e injeção dos pacotes na rede, de forma que seja possível efetuar alterações nas
mensagens determinadas pelo operador do software durante a análise fornecida pelo mesmo.
O objetivo geral do trabalho é a redução no tempo de implantação de sistemas
baseados em VoIP através do desenvolvimento de uma ferramenta capaz de gerar um registro
da troca de sinalização para a análise. Após a análise, a ferramenta deve permitir a alteração
dos pacotes com base na análise do operador ou nas informações recebidas através de regras
pré-estabelecidas para uma posterior injeção desses pacotes e geração de um novo registro
para uma nova análise.
1.4 OBJETIVOS ESPECÍFICOS
São objetivos específicos do presente trabalho:
a) Criar uma ferramenta que permita capturar, alterar e reinjetar os pacotes do fluxo
de mensagens SIP;
b) Fornecer uma interface adequada ao operador da ferramenta;
c) Validar a ferramenta desenvolvida;
d) Analisar os resultados e definir possíveis melhorias na ferramenta.
22
1.5 LIMITAÇÃO DO ESCOPO
O desenvolvimento da ferramenta limita-se a:
a) Não desenvolver qualquer tipo de dispositivo SIP, sendo que para os testes de
validação serão utilizados dispositivos já existentes;
b) A rede a ser utilizada para a validação da ferramenta será uma rede já existente
que apresente as características que viabilizam o processo de validação;
c) A ferramenta não altera nenhum outro campo que não esteja relacionada ao
protocolo em questão ou ao seu processo funcional;
d) Questões relacionadas ao fluxo de audio das chamadas não serão abordadas.
1.6 ORGANIZAÇÃO DO TRABALHO
A sequência do trabalho está descrita a seguir:
a) O capítulo dois faz um apanhado geral da evolução da telefonia até a criação da
VoIP dando uma atenção especial ao protocolo SIP e suas características;
b) O capítulo três trata do desenvolvimento do software proposto;
c) O capítulo quatro determina os testes a serem realizados para a validação do
software;
d) No capítulo cinco é feita a exposição dos resultados obtidos no processo de
validação e as considerações finais em relação ao trabalho como conclusão e
trabalhos futuros.
23
2 REVISÃO BIBLIOGRÁFICA
A partir da invenção do telefone, o crescimento da demanda pela sua utilização foi
significativo. Novos serviços e novos equipamentos surgiram e com eles novos cenários se
tornaram comuns no contexto das telecomunicações (WALLINGFORD, 2005).
A partir da interconexão de dois ou mais telefones surgiu a necessidade de um meio
físico comum entre esses equipamentos para que o sinal fosse transmitido de um telefone para
outro, dando motivação para a criação das centrais telefônicas. No contexto de uso privado
surgiu igualmente um novo equipamento compartilhando esse meio comum, o qual foi
denominado de PBX ou Private Branch Exchange. Esses equipamentos usam o conceito de
comutação de circuitos que é detalhado na próxima seção (WALLINGFORD, 2005).
2.1 COMUTAÇÃO DE CIRCUITOS
Para Goleniewski (2006), a comutação de circuitos foi a base da telefonia desde a sua
criação. A principal característica desse tipo de comutação é a alocação do circuito durante
todo o tempo da comunicação entre os dois equipamentos interconectados e isso requer que
um circuito esteja previamente configurado entre eles, ressaltando-se que quando a
comunicação é encerrada o circuito é liberado. Antes mesmo da comunicação propriamente
dita, nesse tipo de comutação se faz necessário uma requisição partindo da origem até o
destino. Depois de alocado o circuito e o destino ter sido notificado sobre a comunicação é
que se inicia a transmissão do sinal desejado. Na Figura 1, um exemplo de comunicação
baseada na comutação de circuitos, pode-se observar circuitos alocados permanentemente
representados pela linha fixa e circuitos alocados por demanda ou quando a comunicação é
estabelecida representados pela linha tracejada.
24
Figura 1 - Comunicação baseada em comutação de circuitos. Fonte: (GOLENIEWSKI, 2006)
2.2 COMUTAÇÃO DE PACOTES
Da origem da comutação de pacotes pode-se observar:
"Enquanto a comutação de circuitos foi inventada para facilitar a comunicação de
voz, a comutação de pacotes teve sua origem na comunicação de dados."
(GOLENIEWSKI, 2006)
A comutação de pacotes teve sua origem na comunicação de dados e se baseou no
processamento interativo de dados. A primeira geração do processamento de dados foi o
processamento em lote. Nesse caso, o sujeito que estava gerenciando ou produzindo os dados
o fazia através de um terminal e armazenava os dados em cartões perfurados que
posteriormente evoluíram para fitas e depois para discos magnéticos. Depois de armazenados,
os dados eram transmitidos a um host1 que era responsável pelo processamento desses dados.
A transmissão era caracterizada pelo uso de um circuito comutado e por gerar um fluxo de
dados alto e constante (GOLENIEWSKI, 2006).
Ao contrário do processamento em lote, o processamento interativo é feito online2,
sendo que essencialmente o tráfego de dados só existe se o usuário pressionar a tecla Enter e
não quando ele estiver editando uma planilha por exemplo. Isso significa um baixo uso da
1 Host: computador que recebe ou envia dados através de um meio de comunicação (GOLENIEWSKI, 2006).
2 online: estado de comunicação constante (GOLENIEWSKI, 2006).
25
conexão que é utilizada em um grande espaço de tempo com um baixo tráfego de dados.
Assim, Goleniewski (2006) afirma que no processamento interativo não é eficiente se utilizar
um circuito comutado, onde existe um tempo de conexão maior com um fluxo de dados
menor que o processamento em lote. A comutação de pacotes foi desenvolvida para aumentar
a eficiência da transmissão que é feita através da multiplexação de pacotes de dados sobre um
circuito virtual. Dessa forma, a utilização dos circuitos é otimizada e a inteligência da rede é
descentralizada, pois os terminais também gerenciam a conexão ao contrário da comutação de
circuitos, que é feita somente por uma entidade centralizada.
2.2.1 Pacotes
Para Tanenbaum (2003), um pacote é essencialmente uma pequena mensagem
enviada por um dispositivo através de um meio compartilhado. Pacotes são enviados para os
comutadores de pacotes que definem o caminho por onde devem ser enviados com base na
informação do cabeçalho do pacote. O cabeçalho possui informações de origem, destino e a
sequência do pacote, sendo que pelo fato de cada pacote ter um tratamento individual pelo
comutador de pacotes, cada pacote pode percorrer um caminho diferente da origem até seu
destino. Percorrendo caminhos diferentes, os pacotes podem chegar de forma desordenada ao
seu destino. Por essa razão, o destino deve ser capaz de reordenar esses pacotes para recompor
a informação contida nos dados de forma correta. Na Figura 2 pode ser observado um
exemplo da comutação de pacotes sendo realizada, onde pacotes que partem de uma origem
para um destino tomam caminhos diferentes.
26
Figura 2 - Comunicação baseada na comutação de pacotes. Fonte: (GOLENIEWSKI, 2006)
2.3 COMPARAÇÃO ENTRE COMUTAÇÃO DE CIRCUITOS E COMUTAÇÃO DE
PACOTES
Segundo Goleniewski (2006), a comutação de pacotes possui uma série de
características negativas, como latência, jitter3 e perda de pacotes, o que geralmente não
ocorre na comutação de circuitos. Por essa razão, uma rede comutada por pacotes não oferece
as mesmas características de operação que uma rede comutada por circuitos, porém, uma rede
comutada por pacotes oferece maior confiabilidade de entrega pelo fato dos pacotes poderem
ser enviados por caminhos diferentes, aumentando a chance de entrega. Redes baseadas em
comutação de pacotes possuem uma bilhetagem4 diferenciada das redes comutadas por
circuitos. A bilhetagem em redes comutadas por pacotes é formulada sobre o volume de
pacotes transmitidos e/ou a banda utilizada (GOLENIEWSKI, 2006).
Para Goleniewski (2006) redes baseadas em comutação de circuitos são consideradas
superiores em termos de atrasos em filas de entrega, tornando assim latência e jitter
3 Jitter: variação do atraso na entrega de um pacote (DAVIDSON, 2008).
4 bilhetagem: ato de taxar pelo seu uso; a taxação pelo uso do telefone é um exemplo de bilhetagem
(GOLENIEWSKI, 2006).
27
previsíveis e sendo consideradas mais eficientes para transmissão de dados em tempo real. Na
Tabela 1 estão descritas algumas diferenças entre redes comutadas por circuitos e comutadas
por pacotes.
Tabela 1 - Comparação entre a rede comutada por circuitos e a rede comutada por pacotes.
CARACTERÍSTICAS COMUTAÇÃO POR
CIRCUITOS
COMUTAÇÃO POR
PACOTES
Origem Telefonia Comum Redes de dados
Orientação ou não à
conexão
Orientado à conexão Ambos
Aplicações Voz em tempo real, fluxo
de mídia,
videoconferência, vídeo-
sob-demanda, aplicações
que precisam de baixo
atraso e baixa perda de
pacotes
Tráfego de dados com
longo tempo de conexão
mas baixo fluxo de dados,
aplicações que toleram
atrasos e perda de pacotes
Latência/atraso/jitter Baixa latência e mínimo
atraso
Sujeita a latência, atrasos e
jitter por causa do
mecanismo de comutação
Inteligência da rede Centralizada Descentralizada
Eficiência da largura de
banda
Baixa Alta
Perda de pacotes Baixa De baixa a alta dependendo
da rede
Fonte: (GOLENIEWSKI, 2006)
28
2.4 MODELOS DE REFERÊNCIA
A comunicação entre dispositivos através de uma rede é realizada segundo as
seguintes afirmações:
"Antes que dois computadores ou dispositivos de rede possam trocar informações,
eles precisam estabelecer uma comunicação, e é onde os protocolos são utilizados.
Um protocolo de rede habilita dois dispositivos a se comunicarem por usar um
conjunto de regras. O modelo OSI e os padrões de protocolo ajudam a assegurar que
os dispositivos de rede estão aptos a trabalhar juntos sobre a rede."
(GOLENIEWSKI, 2006)
Conforme Goleniewski (2006), os modelos de referência ajudam a assegurar a
compatibilidade entre os dispositivos de rede. Junto com os modelos de referência, existem
também os padrões de protocolos que podem ser definidos como um conjunto de regras ou
coleção de componentes responsáveis pela execução de determinadas tarefas. Uma pilha de
protocolos é constituída de vários protocolos, onde alguns podem ser responsáveis pela
comunicação das interfaces de rede com a rede e outros são responsáveis pela leitura das
informações da interface de rede feita pelo computador. Já uma camada pode ser definida
como uma seção da pilha de protocolos que é responsável por realizar tarefas semelhantes.
2.4.1 Modelo OSI
Para Tanenbaum (2003), o modelo de referência OSI (Open Systems
Interconnection) foi criado com a intenção de padronizar os protocolos utilizados na
comunicação entre os sistemas operacionais. OSI significa "Interconexão de Sistemas
Abertos", pois trata da comunicação entre sistemas que estão abertos para comunicar-se com
outros sistemas. Conforme Goleniewski (2006), o modelo OSI teve sua origem em 1970,
devido às várias incompatibilidades existentes entre os fabricantes de computadores, sendo
concebido pela Organização Internacional de Padronização (ISO). O modelo de referência
OSI foi adotado pelos fabricantes de dispositivos de rede e pelos desenvolvedores de software
como um padrão de comunicação para os seus produtos.
O modelo possui sete camadas que foram criadas com base em alguns princípios:
e) Cada camada possui um nível de abstração diferente;
29
f) Cada camada possui uma função bem definida;
g) As funções das camadas foram definidas buscando a padronização;
h) Os limites das camadas foram definidos buscando a diminuição do fluxo entre as
interfaces;
i) O número de camadas foi definido pequeno o bastante para que o modelo não se
torne complexo e grande o bastante para que funções diferentes não estejam
associadas a mesma camada.
Pode-se observar a Figura 3 que representa as sete camadas do modelo OSI e
também denomina cada unidade em cada camada descrita.
Figura 3 - Modelo de referência OSI.
Fonte: (TANENBAUM, 2003)
30
2.4.2 Modelo TCP/IP
Conforme Tanenbaum (2003), o modelo de referência TCP/IP nasceu de uma
deficiência com a ARPANET, que era uma rede de pesquisa patrocinada pelo Departamento
de Defesa dos Estados Unidos (DoD). A ARPANET conectava várias universidades e
estabelecimentos públicos através de linhas telefônicas. Com o surgimento dos rádios e
satélites, os protocolos até então utilizados apresentavam alguns problemas de interconexão e
foi necessário então a criação de um novo modelo que tinha como principal característica a
conexão de várias redes de forma transparente. Outra necessidade que alavancou o
desenvolvimento de um novo modelo foi a diversidade de exigências das aplicações utilizadas
sobre a rede que variava de uma simples troca de arquivos até uma conversação telefônica
feita em tempo real.
O modelo TCP/IP possui apenas quatro camadas e várias semelhanças com o modelo
OSI. Pode ser observado na Figura 4 o modelo de referência TCP/IP juntamente com o
modelo OSI.
Figura 4 - Modelo de referência TCP/IP. Fonte: (TANENBAUM, 2003)
31
2.4.2.1 Camada de Inter-redes
Dadas as necessidades da criação de um novo modelo, a camada de inter-redes foi
criada em semelhança a camada de rede do modelo de referência OSI. Basicamente a função
desta camada é fazer com que os pacotes cheguem ao seu destino. Ela é responsável também
por assuntos como congestionamento e endereçamento. Pelo fato dela ser uma camada não
orientada à conexão, ela trata cada pacote de maneira individual e por isso cada um deles pode
tomar um caminho diferente até o seu destino. Tomando caminhos diferentes, existe a
possibilidade dos pacotes chegarem ao seu destino em ordem incorreta, a reorganização
desses pacotes é tarefa de outra camada. O protocolo utilizado pela camada de inter-redes para
garantir a entrega dos pacotes é o chamado protocolo IP (Internet Protocol). Ele é utilizado
para endereçar os pacotes conforme sua origem e destino fazendo com que a camada de inter-
redes baseada neste sistema de endereçamento seja capaz de enviá-lo para o seu correto
destino (TANENBAUM, 2003). A Figura 5 mostra os campos do pacote IP.
Figura 5 - Campos do pacote IP. Fonte: (DAVIDSON, 2008)
Os campos observados na Figura 5 são definidos como:
a) Versão - indica a versão do IP que está sendo utilizada IPv4 ou IPv6.
b) Comprimento do cabeçalho IP (CCIP) - indica o tamanho do cabeçalho do
pacote em múltiplos de 32 bits.
32
c) Tipo de serviço - especifica como um protocolo da camada superior deve
tratar este pacote e também através deste campo pode-se atribuir níveis de QoS para
cada pacote.
d) Comprimento total - especifica o tamanho total do pacote IP somando o
cabeçalho IP e os dados em bytes.
e) Identificador - campo que identifica o pacote, utilizado para uma possível
reorganização no caso de fragmentação de pacotes.
f) Flags - 3 bits sendo que os 2 menos significativos controlam a fragmentação e
o mais significativo não é utilizado.
g) Tempo de vida (TTL) - esse campo especifica um contador que é
decrementado gradualmente em cada salto para evitar que pacotes fiquem girando
infinitamente na rede.
h) Protocolo - especifica qual protocolo da camada superior deve tratar os dados
depois do nível IP.
i) Checksum do cabeçalho - número utilizado para verificar se o cabeçalho está
ou não corrompido.
j) Endereço de origem - endereço de origem do pacote.
k) Endereço de destino - endereço de destino do pacote.
l) Opções - algumas opções que o pacote suporta a nível de segurança.
m) Dados - os dados da camada de aplicação bem como informações de
protocolos de nível superior.
2.4.2.1.1 Checksum IP
Como observado no cabeçalho IP, o checksum é um número utilizado para verificar a
integridade do cabeçalho IP. Ele garante apenas a verificação da integridade do cabeçalho,
cabendo aos protocolos das camadas superiores a garantia da integridade desses protocolos e
dos dados por eles transportados (STEVENS, 1993).
Para a determinação do número de checksum, é utilizado o cabeçalho IP dividido em
conjuntos de 16 bits cada, considerando o campo do checksum zerado, é efetuado um cálculo
chamado de “complemento de um” que resulta em uma palavra de 16 bits. Essa palavra é
então adicionada ao cabeçalho IP para que o dispositivo de destino possa verificar a
33
integridade do cabeçalho IP (STEVENS, 1993). Detalhes do cálculo e do algoritmo utilizado
vide ANEXO A.
2.4.2.2 Camada de Transporte
A camada de transporte, como no modelo OSI, tem a função de manter um diálogo
entre a origem e o destino. Nesta camada do modelo TCP/IP, dois protocolos são definidos:
TCP e UDP. O protocolo TCP (Transmission Control Protocol) é orientado à conexão e
possui um controle de entrega baseado em confirmação de recebimento, o que transforma o
TCP em um protocolo confiável. Já o protocolo UDP (User Datagram Protocol) não é
orientado à conexão e não possui um sistema de confirmação de entrega. O protocolo UDP é
geralmente utilizado quando a entrega rápida é mais importante que a entrega confiável, isso
pelo fato do protocolo TCP com seu método de confirmação de recebimento gerar mais
tráfego do que o protocolo UDP e consequentemente demandar mais tempo na troca de
informações (TANENBAUM, 2003).
Na Figura 6 pode-se observar o cabeçalho UPD.
Figura 6 – Cabeçalho UDP. Fonte: (TANENBAUM, 2003).
O cabeçalho UDP possui quatro campos:
a) Porta de Origem - identifica o processo do qual o pacote originou.
b) Porta de Destino - identifica o processo para o qual o pacote deve ser entregue.
c) Comprimento - especifica o tamanho total do pacote UDP somando o cabeçalho
UDP e os dados por ele transportados em bytes.
d) Checksum - número utilizado para verificar a integridade do cabeçalho UDP e
dos dados que ele carrega.
34
2.4.2.2.1 Checksum UDP
O checksum do protocolo UDP é utilizado para verificar a integridade do cabeçalho
UDP e dos dados por ele transportados. O cálculo do checksum do cabeçalho UDP é efetuado
a partir de um bloco de dados chamado pseudo-header, o cabeçalho UDP e o bloco de dados
transportados pelo UDP (STEVENS, 1993).
Os dados utilizados para a determinação do checksum UDP são divididos em
conjuntos de 16 bits cada. Devido ao bloco de dados transportados pelo protocolo UDP ser
variável, pode ocorrer a situação em que o número de conjuntos de 8 bits seja ímpar, o que
inviabiliza o cálculo do checksum por não possuir um número inteiro de palavras de 16 bits.
Quando isso ocorrer, deve-se adicionar uma palavra de 8 bits ao fim do bloco chamada de pad
byte, deixando em número par o total de conjuntos de 8 bits. O pad byte é caracterizado por
ser uma palavra de 8 bits zerada (STEVENS, 1993). Na Figura 7 pode-se observar os campos
que compões o pseudo-header.
Figura 7 - Campos utilizados para o cálculo do checksum UDP. Fonte: (STEVENS, 1993)
O algoritmo utilizado pode ser verificado no ANEXO A.
35
2.4.2.3 Camada de Aplicação
A camada de aplicação é a camada mais alta no modelo TCP/IP, assim como no
modelo OSI. No caso do modelo TCP/IP, não existem as camadas de sessão e apresentação. A
camada de aplicação fica responsável por todos os protocolos utilizados pelos usuários, como
exemplos pode-se citar o FTP (File Transfer Protocol) utilizado para a transferência de
arquivos e o SMTP (Simple Mail Transfer Protocol) utilizado para a troca de e-mails através
da rede (TANENBAUM, 2003).
2.4.2.4 Camada de Infraestrutura de Rede
Esta camada não é realmente especificada pelo modelo TCP/IP. O modelo não
especifica nenhum protocolo desta camada, somente comenta que deve existir um protocolo
através do qual o pacote deve ser enviado (TANENBAUM, 2003).
Na Figura 8 pode-se observar a distribuição dos protocolos comentados nas camadas
do modelo TCP/IP.
Figura 8 - Protocolos no modelo TCP/IP. Fonte: (TANENBAUM, 2003)
36
2.5 VOZ SOBRE IP
Pode-se definir VoIP como:
"[...]VoIP refere-se a ação específica de transmitir dados de som digitalizado em
uma rede IP[...]" (WALLINGFORD, 2005)
Conforme Wallingford (2005), a VoIP é definida como o ato de transmitir som sobre
uma rede IP, ou mais especificamente voz. Uma das vantagens da VoIP está relacionada a
convergência, enquanto um sistema de telefonia comum necessita de uma rede totalmente
separada e específica, a VoIP consegue utilizar a infraestrutura da rede de dados existente
tornando a logística de implantação mais simples na questão física.
A VoIP utiliza dois protocolos para conseguir estabelecer a comunicação e transmitir
o som digitalizado: o protocolo de sinalização e o protocolo de transmissão multimídia. O
protocolo de sinalização tem a função de estabelecer e negociar os detalhes da comunicação e
o protocolo multimídia tem a função de fazer a transmissão do som digitalizado. Comumente
um dos protocolos de sinalização utilizado é o SIP, e um dos protocolos utilizado para a
transmissão de mídia utilizado é o RTP ou "Real-time Transport Protocol" (DAVIDSON,
2008).
2.5.1 RTP
O protocolo RTP possui suas funções definidas dentro das necessidades de uma
transmissão em tempo real.
"A parte de dados do RTP é um protocolo que dá suporte para aplicações com
propriedades de tempo real, como uma mídia contínua (por exemplo, áudio e vídeo),
incluindo reconstrução temporal, detecção de perda e identificação de conteúdo."
(DAVIDSON, 2008)
Conforme Davidson (2008), o RTP é responsável pelos detalhes da comunicação em
tempo real. Reconstrução temporal, detecção de perdas e identificação de conteúdo são
algumas das funções do protocolo RTP. Na Figura 9 pode ser observado o cabeçalho do
protocolo RTP.
37
Figura 9 - Cabeçalho RTP. Fonte: (DAVIDSON, 2008)
Para que a voz, um sinal analógico, seja transmitida através de uma rede em
fragmentos dentro de pacotes, ela precisa antes ser convertida para um sinal digital. Segundo
o teorema de Nyquist, para se amostrar um sinal analógico, é preciso utilizar uma frequência
de amostragem duas vezes maior que a frequência que se pretende amostrar (DAVIDSON,
2008). Outra questão relevante é a resolução da quantização, que significa o número de bits
que cada amostra possui. Quanto maior o número de bits maior a resolução do sinal
amostrado, quanto maior a resolução do sinal amostrado mais ele se assemelha ao sinal
original analógico. O padrão de modulação dos sistemas de telefonia é a modulação PCM
(Pulse Code Modulation) que utiliza uma frequência de amostragem de 8kHz e uma resolução
com escala logarítmica de 8 bits, gerando uma taxa de 64kbps (DAVIDSON, 2008).
A compressão da voz está relacionada com o número de bits das amostras de voz. A
modulação PCM possui dois métodos de compressão que conseguem estabelecer um bom
nível de resolução utilizando apenas 8 bits graças a um método logarítmico de quantização.
Geralmente, para se atingir o mesmo resultado em uma escala linear de quantização seriam
ncessários 12 ou 13 bits (DAVIDSON, 2008). O método ADPCM (Adaptive Differential
Pulse Code Modulation) que utiliza apenas 4 bits de resolução gerando uma taxa de 32kbps.
Esse tipo de compressão utiliza a variação do sinal como dado ao invés do dado propriamente
dito, conseguindo uma boa resolução com um menor número de bits por amostra
(DAVIDSON, 2008).
Existem padrões especificados pela ITU-T para codificação e compressão de voz que
são comumente utilizados na tecnologia de VoIP, sendo também chamados de codecs. Os
codecs influenciam diretamente na largura de banda necessária para o tráfego de voz
(DAVIDSON, 2008). Na Tabela 2 estão relacionados alguns codecs utilizados hoje e suas
respectivas taxas e tamanhos.
38
Tabela 2 - Lista de codecs comumente utilizados.
CODEC TAXA DE
AMOSTR.
TAXA
DE
BITS
INTERVALO
DE
AMOSTR.
TAMANHO
DA
AMOSTRA
DE VOZ
BANDA
ETHERNET MOS
G.711 8kHz 64kbps 10ms 20ms 87.2kbps 4.1
G.729 8kHz 8kbps 10ms 20ms 31.2kbps 3.92
G.723.1 8kHz 5.3kbps 30ms 30ms 20.8kbps 3.8
G.723.1 8kHz 6.3kbps 30ms 30ms 21.9kbps 3.9
Fonte: (CISCO, 2006)
De acordo com a Tabela 2, existem algumas diferenças entre os codecs quanto as
taxas e tamanhos e também quanto ao MOS. O MOS ou Mean Opinion Score, é um sistema
de medida utilizado para mensurar a qualidade de cada codec do ponto de vista do usuário do
serviço. No caso dos codecs apresentados o que possui maior MOS é o que consegue prover
uma qualidade superior na conversação de acordo com a percepção do usuário do serviço
(DAVIDSON, 2008).
2.5.2 SIP
O SIP ou Session Initiation Protocol é um protocolo de sinalização baseado no
HTTP capaz de gerenciar sessões multimídia conforme Camarillo (2002):
"SIP estabelece, modifica e termina sessões multimídias."
As principais funções que fazem parte do protocolo SIP (BALBINOT, 2002) são:
a) Localização de pontos terminais;
b) Contatar os pontos terminais para o estabelecimento da sessão;
c) Troca de informações a respeito da mídia a ser utilizada e permitindo assim o
estabelecimento da sessão;
d) Modificação das sessões já iniciadas;
39
e) Finalização das sessões existentes.
No SIP existe um cliente que faz requisições a um servidor que as responde
(CAMARILLO, 2002).
2.5.2.1 Entidades SIP
O protocolo prevê entidades fundamentais para entender a sua arquitetura
(CAMARILLO, 2002), são elas:
a) User Agent (UA): é uma entidade SIP que interage com o usuário
(CAMARILLO, 2002). Por exemplo, se o usuário A precisa estabelecer uma
sessão multimídia com o usuário B, através do PC do usuário A ele vai utilizar
um software que contém um User Agent. O usuário B também possui um UA que
será contatado para o estabelecimento da sessão (CAMARILLO, 2002).
b) Redirect Servers: sua função é ajudar na localização de UAs para o
estabelecimento de sessões (CAMARILLO, 2002). Esse servidor contribui para a
mobilidade do usuário uma vez que ele passa informações de localização quando
um UA tenta ser contatado e depois sai do fluxo de mensagens (BALBINOT,
2002).
c) Proxy Servers: o proxy server possui informações de localização mas participa
de todo o fluxo de mensagens (CAMARILLO, 2002). Quando um UA tenta ser
contatado, o proxy server reencaminha as mensagens SIP para o destino e
continua no fluxo de mensagens se comunicando com a origem e o destino
(CAMARILLO, 2002).
d) Registrars: um registrar é um órgão que aceita o registro e a autenticação de
usuários com a finalidade de localização e identificação dos mesmos, é utilizado
pelo proxy server e pelo redirect server na localização de usuários (BALBINOT,
2002).
2.5.2.2 Requisições SIP
A requisição SIP é formada por uma linha de requisição ou request-line, cabeçalho,
uma linha em branco e o corpo da mensagem como mostrado na Figura 10 com os fundos em
amarelo, azul, vermelho e verde respectivamente.
40
Figura 10 - Exemplo de requisição SIP. Fone: o autor, 2011.
A linha de requisição possui três elementos: o método, o Request-URI ou endereço
de requisição e a versão do protocolo. O método indica o tipo de requisição, o endereço de
requisição indica a quem a requisição é direcionada e a versão indica a versão do protocolo
(CAMARILLO, 2002). Na Figura 11 o método utilizado é o INVITE, o endereço a quem se
destina a requisição é o sip:[email protected] e a versão do protocolo é SIP/2.0.
Figura 11 - Exemplo de linha de requisição. Fone: o autor, 2011.
2.5.2.2.1 Método INVITE
41
O método INVITE é utilizado para convidar um usuário para uma sessão
(CAMARILLO, 2002). Este método pode utilizar o protocolo SDP (Session Description
Protocol) para fazer a descrição da sessão e definir entre demais detalhes o codec a ser
utilizado na sessão. Na Figura 12 pode ser observada uma troca de mensagens onde o método
INVITE é utilizado.
Figura 12 - Método INVITE. Fonte: (CAMARILLO, 2002)
Conforme observado na Figura 12, o UA do usuário João está enviando um convite
para uma sessão através da requisição INVITE para o UA do usuário Maria. Por sua vez o UA
do usuário Maria responde a requisição informando que o aparelho de Maria está despertando.
Quando o usuário Maria atende a chamada aceitando o convite da sessão, o UA do usuário
Maria envia uma mensagem de sucesso para o UA do usuário João (CAMARILLO, 2002).
Quando utilizado o método INVITE existem alguns campos no cabeçalho que são de
uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 3.
Tabela 3 – Campos no cabeçalho de uso obrigatório no método INVITE.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
42
CSeq
Contact
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.2.2 Método ACK
O método ACK é utilizado pela origem da requisição para fazer com que o UA
destino compreenda que o UA origem entendeu a resposta enviada. No caso do INVITE, após
a recepção da mensagem que o usuário Maria aceitou a sessão, o UA do usuário João envia
uma mensagem de ACK informando o entendimento da última mensagem do método INVITE
como pode ser obsevado na Figura 13 (CAMARILLO, 2002).
Figura 13 - Método ACK. Fonte: (CAMARILLO, 2002)
Quando utilizado o método ACK, existem alguns campos do cabeçalho que são de
uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 4.
43
Tabela 4 - Campos no cabeçalho de uso obrigatório no método ACK.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
CSeq
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.2.3 Método CANCEL
O método CANCEL é utilizado para terminar negociações pendentes
(CAMARILLO, 2002). Se por exemplo um UA receber uma requisição de INVITE, ele não
irá parar de processar a requisição até que receba uma mensagem CANCEL vinda da origem
da requisição INVITE. A mensagem CANCEL não tem efeito algum sobre uma sessão já
estabelecida (CAMARILLO, 2002). Na Figura 14 se pode observar com mais detalhes o uso
da mensagem CANCEL.
Figura 14 - Método CANCEL. Fonte: (CAMARILLO, 2002)
44
Como pode ser observado na Figura 14, o método CANCEL foi utilizado para
cancelar uma requisição de INVITE em andamento onde o UA do usuário Maria reponde com
uma mensagem de transação cancelada.
Quando utilizado o método CANCEL existem alguns campos do cabeçalho que são
de uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 5.
Tabela 5 - Campos no cabeçalho de uso obrigatório no método CANCEL.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
CSeq
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.2.4 Método BYE
O método BYE é utilizado para abandonar uma sessão existente ou terminá-la no
caso de apenas dois UAs participarem dela. (CAMARILLO, 2002). No caso de uma sessão
onde vários UAs estão em comunicação, o envio de uma mensagem BYE apenas identifica
que o UA qua a enviou está deixando a sessão (CAMARILLO, 2002). Na Figura 15 está
ilustrado o uso do método BYE para terminar uma sessão pois no exemplo apenas dois UAs
fazem parte dela.
Quando utilizado o método BYE existem alguns campos do cabeçalho que são de
uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 6.
45
Figura 15 - Método BYE. Fonte: (CAMARILLO, 2002)
Tabela 6 - Campos no cabeçalho de uso obrigatório no método BYE.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
CSeq
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.2.5 Método REGISTER
O método REGISTER é utilizado pelo UA para enviar ao registrador sua localização
e às vezes sua autentição (CAMARILLO, 2002). Na Figura 16 pode-se observar o uso do
método REGISTER onde no exemplo é utilizado apenas para a localização do UA.
46
Figura 16 - Método REGISTER. Fonte: (CAMARILLO, 2002)
Quando utilizado o método REGISTER existem alguns campos do cabeçalho que são
de uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 7.
Tabela 7 - Campos no cabeçalho de uso obrigatório no método REGISTER.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
CSeq
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.2.6 Método OPTIONS
O método OPTIONS é utilizado para perguntar ao destino quais os métodos
suportados e quais os protocolos suportados (CAMARILLO, 2002). Se for utilizado o método
OPTIONS e o destino responder que suporta os métodos INVITE, ACK, CANCEL, BYE e
OPTIONS, pode-se deduzir que ele não seja um registrador, pois não suporta o método
REGISTER (CAMARILLO, 2002).
Quando utilizado o método OPTIONS existem alguns campos do cabeçalho que são
de uso obrigatório (JOHNSTON, 2009) e estão listados na Tabela 8.
47
Tabela 8 - Campos no cabeçalho de uso obrigatório no método OPTIONS.
CAMPOS DO CABEÇALHO
Via
To
From
Call-ID
CSeq
Max-Forwards
Fonte: (JOHNSTON, 2009)
2.5.2.3 Respostas SIP
Uma resposta a uma requisição segue o mesmo padrão da requisição, porém, ao
invés de uma linha de requisição a resposta tem como seu primeiro elemento a linha de estado
ou status line (CAMARILLO, 2002). Na Figura 17 está o estado da linha com fundo amarelo
e os cabeçalhos com fundo azul.
Figura 17 - Exemplo de resposta SIP. Fonte: o autor, 2011.
A linha de estado também possui três elementos: a versão do protocolo, o código de
estado e uma frase. A versão mostra a versão do protocolo que está sendo utilizado, o código
48
de estado representa o estado da transação e a frase mostra o estado da transação sem a
necessidade de interpretação do código de estado (CAMARILLO, 2002). Na Figura 18 a
versão do protocolo é a SIP/2.0, o código de estado é o 401 e a frase é Unauthorized, isso
significa que ocorreu um erro no cliente com código 401 indicando uma falta de autorização.
Figura 18 - Exemplo de linha de estado. Fonte: o autor, 2011.
Os estados estão divididos em classes, cada classe possui um significado. Essas
classes se identificam por códigos que estão dentro da faixa compreendida entre 100 e 699
(CAMARILLO, 2002). Na Tabela 9 pode-se observar todas as classes e seus respectivos
significados.
Tabela 9 - Classes das mensagens de resposta SIP.
FAIXA SIGNIFICADO DA RESPOSTA
100-199 Informação
200-299 Sucesso
300-399 Redirecionamento
400-499 Erro no Cliente
500-599 Erro no Servidor
600-699 Falha Global
Fonte: (CAMARILLO, 2002)
Já na Tabela 10 estão descritas as mensagens de resposta SIP com seus respectivos
códigos.
Tabela 10 - Mensagens SIP.
CÓDIGO MENSAGEM CÓDIGO MENSAGEM
100 Trying 414 Request-URI Too Long
180 Ringing 415 Unsupported media type
181 Call is being forwarded 420 Bad extension
182 Queued 480 Temporarily not available
49
183 Session progress 481 Call leg/transaction does not exist
200 OK 482 Loop detected
202 Accepted 483 Too many hops
300 Multiple choices 484 Address incomplete
301 Moved permanently 485 Ambiguous
302 Moved temporarily 486 Busy here
305 Use proxy 487 Request cancelled
380 Alternative service 488 Not acceptable here
400 Bad request 491 Request Pending
401 Unauthorized 493 Undecipherable
402 Payment required 500 Internal servere error
403 Forbidden 501 Not implemented
404 Not found 502 Bad gateway
405 Method not allowed 503 Service unavailable
406 Not acceptable 504 Gateway time-out
407 Proxy authentication required 505 SIP version not supported
408 Request time-out 513 Message Too Large
409 Conflict 600 Busy everywhere
410 Gone 603 Decline
411 Length required 604 Does not exist anywhere
413 Request entity too large 606 Not acceptable
Fonte: (ROSENBERG, 2002)
2.5.2.4 Campos do Cabeçalho
Segundo Camarillo (2002), os campos do cabeçalho carregam informações da
requisição ou da resposta à requisição. Alguns campos são utilizados somente nas requisições
ou nas respostas às requisições enquanto alguns são utilizados em ambos os casos.
50
2.5.2.4.1 From
O campo From identifica o originador da requisição que é um dos endereços usados
na identificação do diálogo. Juntamente com a identificação do originador, o campo From
pode informar o nome do originador. Pode conter também uma tag ou etiqueta utilizada para
identificar a chamada, essa etiqueta é formada por um número aleatório de no mínimo 32 bits
(JOHNSTON, 2009). Na Figura 19 o campo From identifica que o originador é o
sip:[email protected] de nome TCC e a etiqueta que identifica a chamada é 7136ca6e.
Figura 19 - Exemplo do campo From retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
2.5.2.4.2 To
O campo To indica quem deve receber a requisição. Todas as respostas geradas pelo
proxy server devem conter este campo juntamente com a etiqueta que identifica a chamada, o
usuário que gera a chamada não coloca etiqueta no campo To a não ser que mais de um
campo Via possa existir no cabeçalho. O campo To pode conter também o nome do usuário
que deve receber a requisição além de sua identificação (JOHNSTON, 2009). A Figura 20
identifica que o destino da requisição é sip:[email protected].
Figura 20 - Exemplo do campo To retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
51
2.5.2.4.3 Via
O campo Via é utilizado para rotear as respostas para a origem da requisição. Esse
campo carrega o nome e a versão do protocolo, o nome do protocolo de transporte e o
endereço da origem. Além do endereço, esse campo carrega também uma etiqueta chamada
branch que contém informações dos campos To, From, Call-ID e do elemento Request-URI.
Ele pode conter também o elemento rport onde o proxy server preenche este elemento com o
número da porta a qual ele recebeu a requisição (JOHNSTON, 2009). Na Figura 21 pode-se
observar a versão do protocolo SIP/2.0, o protocolo de transporte UDP, o endereço de origem
da requisição 192.168.33.100:9195, a etiqueta branch=z9hG4bK-d87543-785719176-1--
d87543- e o elemento rport em branco.
Figura 21 - Exemplo do campo Via retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
2.5.2.4.4 Call-ID
O campo Call-ID é obrigatório em todas as mensagens SIP, ele carrega a
identificação de uma sessão entre dois UAs. Esse campo é formado por um número criado de
forma aleatória pelo UA e não é modificado pelo servidor (JOHNSTON, 2009). No exemplo
da Figura 22 o campo Call-ID possui a identificação 3d4a33459546e23f.
Figura 22 - Exemplo do campo Call-ID retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
52
2.5.2.4.5 CSeq
O campo Cseq é obrigatório em todas as mensagens de requisição. Usualmente este
campo possui um número decimal que incrementa a cada nova requisição. Ele é utilizado pelo
servidor para identificar se a mensagem faz parte de uma nova requisição ou de uma
requisição já efetuada. Na Figura 23 o campo Cseq é preenchido com 1 INVITE.
Figura 23 - Exemplo do campo CSeq retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
2.5.2.4.6 Contact
O campo Contact é utilizado para identificar o recurso requisitado ou o originador da
requisição dependendo se o campo faz parte de uma mensagem de requisição ou de resposta.
Essa identificação é utilizada nas mensagens de requisição INVITE ou de resposta 200 OK às
requisições INVITE para criar uma espécie de registro permitindo que requisições futuras
possam ser feitas diretamente ao UA sem o uso de proxy servers (JOHNSTON, 2009). Na
Figura 24 o campo Contact é igual a <sip:[email protected]:9195>.
Figura 24 - Exemplo do campo Contact retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando tanto em requisições quanto em respostas às requisições
(JOHNSTON, 2009).
2.5.2.4.7 Max-Forwards
53
O campo Max-Forwards é usado para indicar o número máximo de saltos que uma
mensagem SIP pode fazer. A cada novo salto esse campo é decrementado. No caso do proxy
server receber uma mensagem SIP com este campo zerado, a mensagem é descartada e é
gerada uma resposta com a linha de estado igual a 483 Too Many Hops que indica que o
número de saltos ultrapassou o permitido (JOHNSTON, 2009). Na Figura 25 pode-se
observar que o campo Max-Forwards é igual a 70, sendo assim esta mensagem pode ainda
passar por até 70 saltos.
Figura 25 - Exemplo do campo Max-Forwards retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando apenas em requisições (JOHNSTON, 2009).
2.5.2.4.8 WWW-Authenticate
O campo WWW-Authenticate é utilizado quando uma autenticação é solicitada a um
UA. Junto com esse campo são informados tipo de algoritmo utilizado (geralmente MD5), o
realm utilizado na autenticação e o nonce também utilizado na autenticação (JOHNSTON,
2009). Na Figura 26 o campo WWW-Autehnticate informando o algoritmo MD5,
realm=“asterisk” e nonce=“0cdf8f98”.
Figura 26 - Exemplo do campo WWW-Authenticate retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando apenas em respostas (JOHNSTON, 2009).
2.5.2.4.9 Authorization
54
O campo Authorization é utilizado para carregar as credenciais do usuário SIP e mais
algumas informações utilizadas pelo servidor SIP para completar a autenticação. Fazem parte
do campo Authorization os elementos username, realm, nonce, uri, response e algorithm
informando o usuário para a autenticação, o realm informado pelo servidor no campo WWW-
Authenticate, o nonce informado pelo servidor no campo WWW-Authenticate, o uri, a resposta
gerada pelo algoritmo de criptografia e o tipo de algoritmo utilizado na criptografia
(JOHNSTON, 2009). Na Figura 27 pode-se observar um exemplo do campo Authorization.
Figura 27 - Exemplo do campo Authorization retirado de uma requisição SIP. Fonte: o autor, 2011.
Este campo é utilizando apenas em requisições (JOHNSTON, 2009).
2.5.2.5 Autenticação do SIP
Existem várias formas de efetuar a autenticação de um UA SIP, uma delas é a
autenticação Digest baseada no protocolo HTTP. Utilizando a autenticação Digest, o servidor
faz a requisição para o cliente enviar a senha criptografada pelo algoritmo MD55
(JOHNSTON, 2009). O envio da senha criptografada previne contra ataques, pois se o pacote
que contém as informações de autenticação for interceptado no meio do caminho, a senha não
poderá ser visualizada (JOHNSTON, 2009).
A requisição de autenticação é feita através da resposta 401 Unauthorized. No
mesmo pacote da resposta é enviado um campo chamado WWW-Authenticate que possui
algumas informações utilizadas na criptografia da senha. Recebendo a requisição e essas
informações, o usuário deve enviar um pacote com o mesmo método utilizado no início da
conversação com o campo Authorization. Nesse campo são enviadas as informações
utilizadas para criar a criptografia da chave além da própria chave (JOHNSTON, 2009).
O algoritmo MD5 utilizado para a criptografia da chave converte uma mensagem de
qualquer tamanho em uma assinatura de 128 bits. A partir de uma mensagem criptografada
5 MD5 ou Message-Digest Algorithm 5 pode ser definido como um algoritmo de criptografia (ABZUG, 1991).
55
com o algoritmo MD5 é impossível obter a mensagem original, portanto, a autenticação se dá
comparando a criptografia gerada na origem com a criptografia gerada no destino, ambas
geradas a partir dos mesmos dados (ABZUG, 1991).
No SIP, a mensagem utilizada para criar a criptografia é formada por alguns
elementos do cliente e outros elementos do servidor. No caso do cliente, são utilizadas as
informações de username, password, uri e método utilizado. No caso do servidor são
utilizadas as informações de realm e nonce (KRIVUTSENKO'S, 2006). Como visto na seção
anterior, o servidor envia para o cliente as informações utilizadas na autenticação no campo
WWW-Authenticate e o cliente responde com as informações de autenticação no campo
Authorization.
O padrão utilizado para a criação da criptografia de autenticação é formado através
da geração de três diferentes chaves:
- A primeira chave é criada a partir das informações de username, realm e password
(KRIVUTSENKO'S, 2006);
- A segunda chave é criada a partir das informações de método e uri
(KRIVUTSENKO'S, 2006);
- A terceira e última chave, que é exatamente a mensagem criptografada a ser
enviada no pacote de autenticação, é criada a partir da primeira chave, do nonce e da segunda
chave (KRIVUTSENKO'S, 2006).
A primeira chave é criada a partir da mensagem mostrada na Figura 28.
Figura 28 - Geração da primeira criptografia. Fonte: o autor, 2011.
A segunda chave é criada a partir da mensagem mostrada na Figura 29.
Figura 29 - Geração da segunda criptografia. Fonte: o autor, 2011.
A terceira e última chave é criada a partir da mensagem mostrada na Figura 30.
56
Figura 30 - Geração da terceira criptografia. Fonte: o autor, 2011.
Na Figura 31 pode-se observar um exemplo prático com dados reais.
Figura 31 - Exemplo de criptografia com dados reais. Fonte: o autor, 2011.
2.5.2.6 Vulnerabilidades do SIP
Citando McGann (2005):
"A complexidade da VoIP cria um alto número de vulnerabilidades que afetam as
três áreas clássicas da segurança da informação: confidencialidade, integridade e
disponibilidade"
Conforme afirmação de McGann, a complexidade a qual a tecnologia VoIP é
concebida, cria vulnerabilidades que afetam a segurança da informação. Pode-se destacar
também Johnston (2006):
"Identidade no SIP significa o SIP URI do usuário. Quando uma requisição é
recebida, um UA pode observar o campo "From" do cabeçalho e usar ese como
identidade[...]"
Existem portanto, campos q ue fazem parte do SIP, como é o caso do campo From
que identifica a origem de uma chamada VoIP por exemplo. Nesse caso fica clara a
vulnerabilidade uma vez que um dispositivo pode iniciar a negociação de uma sessão se
fazendo passar por outro dispositivo.
57
"SIP não é um protocolo fácil de assegurar. Seu uso de intermediários, suas relações
multifacetadas confiáveis, suas expectativas de uso entre elementos sem uma total
confiabilidade, e sua operação de usuário-para-usuário faz com que a segurança
esteja longe da trivial." (ROSENBERG, 2002)
Pelo fato do SIP operar em diversos pontos intermediários e entre dispositivos que
podem não ser confiáveis, a segurança no SIP fica a cargo de terceiros uma vez que nele ela
não é ideal.
2.6 BIBLIOTECA LIBPCAP
A biblioteca de desenvolvimento libpcap ou Packet Capture Library, pode ser
definida como:
"A biblioteca de captura de pacotes fornece uma interface de alto nível para sistemas
de captura de pacotes. Todos os pacotes na rede, mesmo que destinados a outros
hosts, são acessíveis através deste mecanismo." (JACOBSON, LERES e
MCCANNE, 2003)
Conforme citado, a biblioteca libpcap fornece suporte a captura de pacotes da rede
de dados mesmo que eles não sejam destinados ao host onde ela se encontra6. Desenvolvida
para a utilização na linguagem de programação C (JACOBSON, LERES e MCCANNE,
2003), ela possui um número considerável de funções definidas que facilitam a captura dos
pacotes. Além da captura, a bilbioteca permite também que sejam injetados pacotes na rede
através de funções específicas. As funções pertinentes a este projeto estão listadas abaixo:
a) pcap_open_live() - esta função é utilizada para criar a sessão de captura dos
pacotes da rede (JACOBSON, LERES e MCCANNE, 2003). Nela são utilizados
argumentos como interface de captura onde será efetuada a captura, tamanho
máximo de bytes a serem capturados, time-out para o encerramento da captura,
modo de captura (promíscuo ou não) e registro de erro ou aviso.
b) pcap_loop() - esta função é utilizada para criar um loop de captura de modo que a
cada novo pacote recebido seja executada uma outra função (JACOBSON,
LERES e MCCANNE, 2003). Ela é importante pelo fato de que a cada novo
pacote recebido, pode-se processá-lo de acordo com a necessidade do
programador.
c) pcap_compile() - esta função é utilizada para compilar o filtro a partir de uma
variável antes de aplicá-lo na sessão de captura (JACOBSON, LERES e
6Para que isso seja possível, é necessário que todos os pacotes (mesmo os não destinados ao host) estejam
chegando até a interface de captura do host.
58
MCCANNE, 2003) de forma que não é necessário se capturar todos os pacotes
da rede, apenas os que se deseja processar.
d) pcap_setfilter() - esta função é utilizada para aplicar o filtro compilado na sessão
de captura (JACOBSON, LERES e MCCANNE, 2003).
e) pcap_inject() - esta função tem a finalidade de injetar um pacote na rede
(JACOBSON, LERES e MCCANNE, 2003). Nela pode se determinar a sessão a
qual o pacote será injetado, o resultado determina se ele foi ou não corretamente
injetado.
f) pcap_dispatch() - esta função é utilizada para efetuar o processamento dos
pacotes após a captura na sessão. É necessário passar argumentos a esta função
como número de pacotes que serão processados e nome da função que irá fazer o
processamento do pacote (JACOBSON, LERES e MCCANNE, 2003).
g) pcap_lookupnet() - esta função é utilizada para obter os dados de endereço e
máscara da interface utilizada para fazer a captura necessários para a aplicação
do filtro de captura na sessão (JACOBSON, LERES e MCCANNE, 2003).
h) pcap_setnonblock() - esta função é utilizada para bloquear ou não a sessão de
captura, se bloqueada, a execução da função de captura fica aguardando a captura
de algum pacote ao invés de executar a próxima linha de código (JACOBSON,
LERES e MCCANNE, 2003).
2.6.1 Captura de Pacotes Utilizando a LIBPCAP
A captura pode ser definida como:
“Captura de pacotes nos permite interceptar qualquer pacote que é visto pelo
dispositivo de rede, e pegá-lo com os cabeçalhos e tudo! Independentemente em
qual porta está sendo enviado, ou mesmo qual host!” (CASADO, 2001)
Segundo Casado (2001), a captura de pacotes permite que qualquer pacote seja
capturado independente de quem o está enviando ou para quem está enviando. Isso torna
possível a idéia de que um host pode capturar um pacote destinado a outro host e ver todas as
informações contidas neste pacote.
A sessão de captura pode ser considerada uma tarefa simples:
“A tarefa de criar uma sessão de sniffing é realmente muito simples. Para isso,
usamos pcap_open_live().” (CARSTENS, 2002)
59
Conforme Carstens (2002), a tarefa de criar uma sessão de sniffing7é simples, como
pode ser observada na Figura 32 que mostra algumas linhas de código criando uma sessão de
captura.
Figura 32 - Código para criação de uma sessão de captura. Fonte: (CARSTENS, 2002)
O código observado na Figura 32, abre o dispositivo armazenado na variável
somedev e lhe diz para ler tantos bytes quantos são especificados em BUFSIZ (que é definido
no pcap.h). É informado também para a interface ser colocada em modo promíscuo, ou seja,
capturar pacotes até que um erro ocorra, e se algum erro ocorrer uma mensagem é impressa na
tela (CARSTENS, 2002).
2.6.2 Filtros de Captura Utilizados com a LIBPCAP
Os filtros de captura são utilizados no caso em que se tem interesse em apenas parte
do tráfego da rede (CARSTENS, 2002). Um filtro de captura precisa ser compilado antes de
ser aplicado na sessão de captura (CARSTENS, 2002) e a função de compilação pode ser
observada na Figura 33.
Figura 33 - Compilação de um filtro de captura. Fonte: (CARSTENS, 2002)
Após a compilação, o filtro pode ser então aplicado na sessão de captura. Para isso é
preciso utilizar a função descrita na Figura 34 (CARSTENS, 2002).
7 Sessão de sniffing neste contexto pode ser definida como uma sessão de captura.
60
Figura 34 Aplicação de um filtro de captura em uma interface. Fonte: (CARSTENS, 2002)
A expressão de um filtro define-se como:
“A expressão de filtro consiste de uma ou mais primitivas. Primitivas geralmente
consistem de um ID (nome ou número) precedidas de um ou mais qualificadores.”
(JACOBSON, LERES e MCCANNE, 2008)
Conforme definição, um filtro é definido por um ou mais primitivas e uma primitiva
consiste em um nome ou número precedido de um qualificador. Nos filtros utilizados na
libpcap existem três diferentes qualificadores que podem ser utilizados:
a) Tipo - define no que o filtro é aplicado. Os tipos possíveis são host, net, port e
portrange que significam o host ou dispositivo, a rede a porta ou faixa de portas
respectivamente (JACOBSON, LERES e MCCANNE, 2008).
b) Dir - define o tipo específico de direcionamento do tráfego a ser filtrado. Os
possíveis valores são src, dst, src or dst e src and dst, significam origem, destino,
origem ou destino, e origem e destino respectivamente (JACOBSON, LERES e
MCCANNE, 2008).
c) Proto - define o tipo específico de protocolo a ser filtrado. Os possíveis valores
são ether, ip, tcp e udp, significam Ethernet, IP, TCP e UDP respectivamente
(JACOBSON, LERES e MCCANNE, 2008).
Na Figura 35 pode ser observado um exemplo de expressão de filtro que pode ser
aplicada, no caso desta expressão, está sendo filtrado todo tráfego destinado e originado do
host 192.168.0.1 que utiliza o protocolo UDP cuja porta de destino é igual a 5060
Figura 35 - Exemplo de expressão de filtro. Fonte: o autor, 2011.
2.6.3 Exemplo de Código
Conforme Carstens (2002), o código mostrado na Figura 36 pode servir como
exemplo do uso da biblioteca libpcap.
61
Figura 36 - Exemplo de código utilizando libpcap. Fonte: (CARSTENS, 2002)
Observando o código mostrado, são declaradas algumas variáveis como handle que
representa a sessão de captura, dev que armazena o nome da interface utilizada para a captura,
errbuf que armazena possíveis erros na execução das funções da biblioteca, fp que é a
estrutura onde o filtro deve ser compilado, filter_exp que guarda a expressão do filtro de
captura, mask que armazena a máscara da interface de rede e net que armazena o endereço IP
da interface de rede (CARSTENS, 2002).
Depois de declaradas as variáveis, a função pcap_lookupdev utilizada para descobrir
as informações de endereçamento e máscara da interface é executada. O segundo passo é a
execução da função pcap_open_live que configura e abre a sessão de captura. O terceiro passo
é a compilação do filtro com uso da função pcap_compile e o quarto e último passo é a
aplicação do filtro na sessão de captura com uso da função pcap_setfilter (CARSTENS,
2002).
62
3 IMPLEMENTAÇÃO DO PROTÓTIPO
No capítulo dois foi realizada uma pesquisa bibliográfica sobre os conceitos
fundamentais para a elaboração do analisador SIP que é a proposta deste trabalho. Neste
capítulo serão abordados os assuntos acerca da criação desta ferramenta que visa a análise da
interoperabilidade do SIP entre os dispositivos, dando ao operador a possibilidade de fazer
alterações nos pacotes coletados, e injetar esses pacotes na rede para realizar uma nova
análise.
3.1 METODOLOGIA
No presente trabalho a metodologia utilizada é a que segue:
d) Elaboração de um fluxograma do software proposto detalhando interface com o
operador e as funções de captura, alteração e injeção dos pacotes a fim de guiar o
desenvolvimento.
e) Desenvovimento do analisador SIP proposto seguindo o padrão estabelecido no
fluxograma criado.
f) Validação do analisador SIP através da criação de um cenário real de
implementação de VoIP com o auxílio de ferramentas de apoio.
3.2 FERRAMENTAS UTILIZADAS
Para a elaboração e validação do analisador SIP proposto, foram utilizadas
basicamente quatro ferramentas:
a) Eclipse IDE for C/C++ Developers
b) Wireshark Network Protocol Analyzer
63
c) eyeBeam
d) Asterisk
3.2.1 Eclipse IDE for C/C++ Developers
O Eclipse IDE for C/C++ Developers é uma plataforma que possui uma coleção de
recursos e fornece suporte para criação, edição, navegação, compilação e depuração de
projetos que usam C ou C++ como linguagem de programação. A plataforma não inclui os
compiladores utilizados para converter o código de programação em programas executáveis
ou depurar esses códigos, mas fornece suporte para que essas ferramentas sejam integradas a
plataforma (ECLIPSE, 2011).
Algumas das facilidades que a plataforma fornece é a criação do makefile8 para
auxílio na compilação, ambiente gráfico para a depuração do código e o conceito de
perspectivas para cada tipo de tarefa que está sendo executada, seja programação ou
depuração. Através do uso de perspectivas, simplifica-se a visualização do código em questão
ou das linhas em execução juntamente com valores de variáveis no caso da depuração
(ECLIPSE, 2011). A plataforma é obtida de forma gratuita na página da Fundação Eclipse na
Internet, foi utilizada no sistema operacional Linux, distribuição CentOS versão 5.5 e
interface gráfica Gnome. Na Figura 37 pode-se ter uma visão geral da plataforma Eclipse.
3.2.2 Wireshark Network Protocol Analyzer
O Wireshark é um analisador de pacotes da rede. A função deste é tentar capturar os
pacotes da rede e tentar mostrá-los da forma mais detalhada possível (LAMPING, SHARPE e
WARNICKE, 2011). Existem diversos protocolos que o analisador pode reconhecer e
detalhar ao operador. No presente trabalho foi necessário verificar os pacotes capturados pelo
analisador SIP de forma a comprovar se realmente todo o tráfego gerado pelo dispositivo SIP
8 Makefile pode ser definido como um arquivo que auxilia no processo de compilação de projetos (WALL,
WATSON e WHITIS, 1999).
64
estava sendo capturado, além de comprovar a correta criação dos pacotes injetados pelo
analisador após a alteração dos dados dos pacotes. O Wireshark é obtido de forma gratuita
através da sua página na Internet e foi utilizado no sistema operacional Windows. Na Figura
38 pode-se ter uma visão geral do Wireshark.
Figura 37 - Visão geral do Eclipse. Fonte: o autor, 2011.
Figura 38 - Visão geral do Wireshark. Fonte: o autor, 2011.
65
3.2.3 eyeBeam
O eyeBeam é um software que é utilizado como um telefone SIP, capaz de
estabelecer sessões multimídia com outros usuários SIP (COUNTERPATH, 2011). Na Figura
39 pode-se ter uma visão geral do software. Através da tela mostrada, o usuário pode discar
um número ou o nome de um usuário. Para estabelecer uma sessão multimídia, um servidor
precisa estar cadastrado. Na Figura 40 são mostrados os campos a serem configurados para
que o software tenha acesso a um servidor. Podem ser verificados os campos: display name
que identifica o nome do usuário, o campo user name que identifica o usuário que está
estabelecendo a sessão multimídia, o campo password que armazena a senha do usuário
utilizada para a autenticação do usuário no servidor SIP, o campo authorization user name
que identifica o username utilizado na autenticação do usuário SIP e o campo domain que
identifica o endereço do servidor para o qual as requisições são enviadas.
Figura 39 - Visão geral do eyeBeam. Fonte: o autor, 2011.
66
Figura 40 - Detalhes da configuração do eyeBeam. Fonte: o autor, 2011.
No presente trabalho, o software é utilizado como um dispositivo SIP monitorado
durante o envio das requisições para o servidor. Ele é utilizado durante o desenvolvimento e
da validação do analisador SIP uma vez que a interoperabilidade entre este software e o
servidor, serve como exemplo de negociação do protocolo SIP.
3.2.4 Asterisk
O Asterisk é uma plataforma open source9 de telefonia convergente que foi projetado
primeiramente para rodar em plataforma Linux. Asterisk é um servidor de comunicação com
um conjunto de aplicações de telefonia integrado (MADSEN, MEGGELEN e BRYANT,
2011).
Analisando superficialmente, o Asterisk pode ser definido como um servidor de
comunicação que registra, interliga e controla usuários que precisam se comunicar. Dentre os
protocolos por ele suportados, o SIP é um deles, pode então ser considerado um servidor SIP
(MADSEN, MEGGELEN e BRYANT, 2011).
No desenvolvimento deste trabalho, o Asterisk foi utilizado como uma ferramenta de
apoio para os testes durante o desenvolvimento e a validação do analisador SIP. Nele foram
configurados dois usuários SIP para efetuar os testes. Na Figura 41 pode-se observar o
arquivo que armazena as configurações dos usuários SIP denominado sip.conf (MADSEN,
MEGGELEN e BRYANT, 2011).
9 Open source é o conceito de software livre, que possui código aberto.
67
Figura 41 - Configuração do Asterisk. Fonte: o autor, 2011.
Os usuários identificados como 200 e 300 foram criados e definidos como tipo
friend, fazendo parte do contexto phones e com endereços de host dinâmico. O tipo friend
determina que o reconhecimento do usuário pode ser feito tanto pelo endereço IP de origem
das requisições enviadas quanto pela autenticação de um usuário através de métodos
tradicionais utilizando um nome de usuário e uma senha. O campo secret define a senha de
cada usuário e o campo allow define os protocolos de compressão de audio permitidos para
cada usuário (MADSEN, MEGGELEN e BRYANT, 2011). O contexto situa o processamento
do usuário dentro do plano de numeração criado no arquivo extensions.conf (MADSEN,
MEGGELEN e BRYANT, 2011) que pode ser visualizado na Figura 42.
Figura 42 - Configuração do plano de numeração no Asterisk. Fonte: o autor, 2011.
No plano de numeração configurado foi definido que se algum usuário tentar enviar
requisições para o número 200, elas serão encaminhadas para o usuário SIP identificado como
200 e se algum usuário tentar enviar requisições para o número 300, elas serão encaminhadas
para o usuário SIP identificado como 300.
68
3.3 ELABORAÇÃO DO FLUXOGRAMA
Para a elaboração do fluxograma do analisador SIP proposto, foi necessário fazer a
definição das análises que a ferramenta poderia proporcionar ao operador para depois listar as
principais funções da ferramenta além da organização da interface com o operador.
3.3.1 Análises Possíveis Através da Ferramenta
Foi definido que a ferramenta deveria proporcionar ao operador análises quanto a
identificação do usuário que está efetuando o estabelecimento da sessão multimídia
(denominado ativo no presente trabalho) e a identificação do usuário o qual está sendo
convidado para participar da sessão multimídia (denominado passivo no presente trabalho).
Com base no protocolo SIP e nas análises que a ferramenta deve proporcionar, é possível
definir quais campos do protocolo devem ser observados e alterados, além de ser possível
também definir uma estrutura básica para guiar o desenvolvimento da ferramenta.
3.3.2 Principais Funções do Analisador
Um analisador de protocolos de rede precisa de uma interface de rede e uma rede
como fonte de dados para efetuar a captura dos pacotes e a análise de um protocolo
(LAMPING, SHARPE e WARNICKE, 2011). No caso do analisador SIP proposto, a fonte de
dados é a rede onde os pacotes estão trafegando entre os dispositivos. Para ter acesso a esses
pacotes é necessário o uso de uma interface de rede física conectada a rede onde existe o
tráfego. A primeira função é então estabelecida como a captura dos pacotes da rede.
A segunda função surgiu da necessidade de disponibilizar ao operador uma análise
dos pacotes capturados que representam a interoperabilidade do protocolo em questão, dando
a possibilidade de alteração de alguns dados. Portanto, a segunda função ficou definida como
análise e alteração dos dados dos pacotes coletados.
69
A terceria função partiu da necessidade da injeção dos pacotes alterados para fazer
uma nova análise. Portanto, esta função trata da criação, injeção e sincronismo entre os
pacotes injetados e os pacotes recebidos como resposta.
3.3.3 Organização da Interface com o Operador
Para permitir ao operador o acesso às funções do analisador, foi definida a utilização
de menus baseados em texto puro. Foi definido um padrão de cabeçalho que mostra o nome
do software e informações sobre a seção a qual o operador está acessando no momento. Sete
diferentes opções estão disponíveis na tela principal do software. Na Figura 43 tem-se uma
visão geral do menu principal com o padrão de cabeçalho na parte superior e todas as opções
disponíveis ao operador.
Figura 43 - Visão geral do menu principal. Fonte: o autor, 2011.
70
3.3.3.1 Seção “Escuta”
Dentro da seção “Escuta”, o operador faz a configuração da sessão de captura
definindo a interface através da qual a captura será efetuada, endereço IP do dispositivo
monitorado e a porta de origem ou destino das mensagens SIP. Nesta seção o operador
também inicia e finaliza a sessão de captura visualizando em tempo real os pacotes sendo
capturados com as informações de sequência de pacote, endereço IP de origem, porta de
origem, endereço IP de destino, porta de destino, direcionamento do tráfego e o método SIP
utilizado em cada pacote. Na Figura 44 pode-se visualizar a tela principal dentro da seção
“Escuta”
Figura 44 - Visão geral da seção "Escuta". Fonte: o autor, 2011.
Na Figura 45 pode-se observar a sessão de captura com alguns pacotes capturados e
suas informações.
3.3.3.2 Seção “Dados Escutados”
Dentro da Seção “Dados Escutados”, o operador tem acesso aos pacotes capturados
através da sessão de captura efetuada dentro da seção “Escuta”. É possível visualizar uma
sequência de pacotes, seus endereços IP de origem e destino, portas de origem e destino e o
método SIP utilizado. O acesso a esta seção só é disponibilizado se já existirem pacotes
71
capturados. Dentro desta seção, o operador tem acesso aos campos SIP disponíveis para
alteração, visualizando os valores originais obtidos através da análise dos pacotes capturados.
As alterações efetuadas pelo operador são armazenadas em arquivos para que possam ser
aplicadas no momento da injeção desses pacotes. Não havendo nenhuma alteração, os pacotes
são injetados com os valores originais. Na Figura 46 pode-se observar a tela principal da
seção “Dados Escutados”, visualizando os pacotes capturados na seção de “Escuta” e os
campos SIP disponíveis para a alteração.
Figura 45 - Visão geral da sessão de captura. Fonte: o autor, 2011.
Figura 46 - Visão geral da seção "Dados Escutados". Fonte: o autor, 2011.
72
3.3.3.3 Seção “Injeção”
O acesso a seção “Injeção” é somente disponibilizado se existirem pacotes
previamente capturados e armazenados e se nenhuma sessão de injeção fora anteriormente
realizada. Dentro da seção “Injeção” é possível, ao comando do operador, iniciar o processo
de injeção dos pacotes com as alterações propostas na seção anterior. O cancelamento da
injeção pode ser feito a qualquer momento também sob o comando do operador. Ao passo que
os pacotes são injetados, pode-se visualizar a sequência dos pacotes com as informações de
endereçamento IP de origem e destino, portas de origem e destino e o método SIP utilizado.
Ao término da injeção o operador pode retornar ao menu anterior pressionando qualquer tecla.
Na Figura 47 pode ser observada a seção “Injeção” com alguns pacotes injetados e suas
respectivas informações.
Figura 47 - Visão geral da seção "Injeção". Fonte: o autor, 2011.
3.3.3.4 Seção “Mostrar Resultados”
A seção “Mostrar Resultados” fornece a visualização dos pacotes capturados e
injetados nas seções “Escuta” e “Injeção”. Pode-se através desta opção fazer uma comparação
73
entre as duas seções e observar as diferenças na interoperabilidade do protocolo diante das
alterações efetuadas ou não pelo operador. O acesso a esta seção só é disponibilizado se uma
injeção fora previamente executada. Nesta seção é mostrada a sequência dos pacotes com
endereçamento IP de origem e destino, portas de origem e destino e o método SIP utilizado.
Na Figura 48 tem-se uma visão geral da seção “Mostrar Resultados” com todos os pacotes.
Figura 48 - Visão geral da opção de "Mostrar Resultados". Fonte: o autor, 2011.
3.3.3.5 Seção “Limpar Resultados”
A seção “Limpar Resultados” faz a limpeza dos pacotes capturados e injetados na
seção “Iinjeção”. Essa opção é utilizada sempre que se necessita realizar uma nova injeção.
Na Figura 49 observa-se a mensagem disponibilizada quando a seção “Limpar Resultados” é
acessada.
74
Figura 49 - Visão geral da seção "Limpar Resultados". Fonte: o autor, 2011.
3.3.3.6 Seção “Limpar Tudo”
A seção “Limpar Tudo” faz uma limpeza geral, excluindo todos os dados
armazenados. Essa opção exclui também os arquivos de controle gerados pelo software. Esses
arquivos serão mencionados no decorrer deste trabalho. Na Figura 50 observa-se a mensagem
disponibilizada quando a seção “Limpar Tudo” é acessada.
Figura 50 - Visão geral da seção "Limpar Tudo". Fonte: o autor, 2011.
75
3.3.4 Fluxograma
Depois de definidas as principais funções do software e a interface com o operador,
foi elaborado o fluxograma da ferramenta para servir como guia durante o processo de
programação. A Figura 51 mostra o fluxograma do projeto.
Figura 51 – Fluxograma geral do projeto. Fonte: o autor, 2011.
76
Com base nas funções, na interface com o operador e no fluxograma, o software
pode ser dividido em:
a) Controle principal;
b) Controle de escuta;
c) Controle de visualização e alteração de dados escutados;
d) Controle de injeção;
e) Controle de amostragem de resultados;
f) Controle de limpeza de resultados;
g) Controle de limpeza total.
Fazendo uma primeira análise no fluxograma antes mesmo do início do
desenvolvimento, determinaram-se algumas responsabilidades a cada seção de controle.
A seção de controle principal deve controlar o acesso a todas as outras seções, vai
representar a entidade principal do software sendo inicializada por primeiro e deve também
fazer as adequações necessárias das variáveis globais utilizadas no software.
A seção de controle de escuta deve ser responsável pela configuração do filtro de
captura baseado nos dados de endereço IP de origem e porta de destino informados pelo
operador. Ela é também reponsável por controlar o acesso a interface de rede para efetuar a
captura dos pacotes e salvá-los de forma a serem reutilizados posteriormente.
A seção de controle de visualização e alteração de dados escutados deve controlar a
exposição dos pacotes capturados na seção de escuta, além de controlar as alteração dos
campos SIP.
A seção de controle de injeção deve alterar os dados dos pacotes conforme as
alterações efetuadas nos campos SIP além da criação dos pacotes para a injeção.
Devecontrolar o acesso a interface de rede para fazer a injeção e a captura de pacotes,
controlar o sincronismo de envio e recebimento de pacotes para o dispositivo em
comunicação com o dispositivo monitorado e armazenar esses pacotes enviados e recebidos
para a posterior análise.
A seção de controle de visualização de resultados deve controlar a exposição dos
dados capturados na seção de escuta e dos dados capturados e injetados na seção de injeção.
77
A seção de controle de limpeza de resultados é responsável pela limpeza de todos os
dados obtidos após o processo de injeção de forma a deixar o software preparado para realizar
uma nova injeção.
A seção de controle de limpeza total é responsável pela limpeza geral de todos os
dados armazenados.
3.3.4.1 Determinação do Filtro de Captura
A determinação do filtro de captura se deu com base na pesquisa efetuada sobre o
protocolo SIP e o protocolo IP. Verificando que o pacote IP possui um endereço IP de origem
e um endereço IP de destino, e o mecanismo IP não permite a existência de dois dispositivos
com o mesmo endereço em operação, simultaneamente em uma rede, define-se como parte
necessária do filtro a ser aplicado na captura o endereço IP de origem dos pacotes originados
no dispositivo monitorado e o endereço IP de destino dos pacotes originados no dispositivo
em comunicação com o dispositivo monitorado. Outra parte do filtro diz respeito a porta
utilizada no cabeçalho UDP: tendo por base que o protocolo UDP sempre utiliza uma porta de
origem e uma de destino na comunicação, define-se como parte necessária do filtro a ser
aplicado na captura, a porta de destino dos pacotes originados no dispositivo monitorado e a
porta de origem dos pacotes originados no dispositivo em comunicação com o dispositivo
monitorado (TANENBAUM, 2003).
3.3.4.2 Determinação dos Campos para Alteração
Com base nas análises propostas no item 3.3.1 e no protocolo SIP, definem-se como
os campos passíveis de alteração para o usuário ativo o campo que identifica o originador da
requisição, denominado de caller neste trabalho e os campos que fazem a autenticação do
usuário denominados de username e password neste trabalho.
78
Para o usuário passivo foi definido como passível de alteração o campo que
identifica o convidado da sessão multimídia, denominado de called neste trabalho.
3.4 DESENVOLVIMENTO DO ANALISADOR PROPOSTO
3.4.1 Definições Iniciais
Para facilitar o desenvolvimento, foram definidas algumas funções como globais por
serem utilizadas em diversas áreas do código. Essas funções estão armazenadas em arquivos
separados de forma a facilitar o acesso a elas.
Os pacotes capturados na seção “Escuta” e os capturados e injetados na seção
“Injeção” ficam armazenados em arquivos texto, seguindo um padrão de estrutura e
formatação. Dados das sessões de captura e injeção e informações sobre o filtro de captura
ficam armazenadas em um arquivo texto específico denominado info_sessao.txt também com
estrutura e formatação específicas. Informações sobre os campos SIP ficam armazenadas em
outro arquivo texto denominado capture_data.txt também com estrutura e formatação
específicas.
3.4.2 Padrões de Arquivos Utilizados
Conforme mencionado, os pacotes capturados, os dados de sessões de captura e os
dados referentes aos campos do protocolo SIP, ficam armazenados em arquivos diferentes.
Para cada arquivo foi definido um padrão de armazenamento dos dados.
79
3.4.2.1 Arquivos de Captura
Os arquivos de captura podem ser dividos em arquivos de captura gerados pela seção
“Escuta” e arquivos de captura e injeção gerados pela seção “Injeção”. Eles possuem a
nomenclatura diferenciada, porém, o padrão de armazenamento dos dados dos pacotes é
exatamente o mesmo. Os padrões de nomenclatura dos arquivos de captura são:
a) Arquivos capturados através da seção “Escuta” - estes arquivos são
denominados capture_xx.cap, sendo “xx” um número de dois algarismo
representando a sequência de captura.
b) Arquivos capturados através da seção “Injeção” - estes arquivos são
denominados capture_res_xx.cap, sendo “xx” um número de dois algarismo
representando a sequência de captura.
Os arquivos são formados por duas partes distintas: uma separa e identifica todos os
campos dos cabeçalhos Ethernet, IP e UDP, e a outra constitui o bloco de dados do protocolo
SIP. Na Tabela 11 observa-se um exemplo de arquivo de captura, os números visualizados à
esquerda são identificações das linhas do arquivo, não fazendo parte do conteúdo.
Tabela 11 - Exemplo de arquivo de captura. 1 ARQ_NUM=01
2
3 ETHER_MAC_SRC=0:C:29:68:26:3A;
4 ETHER_MAC_DST=0:C:29:41:58:95;
5 ETHER_TYPE=8
6
7 IP_VER=69
8 IP_TOS=0
9 IP_LEN=746
10 IP_ID=1374
11 IP_OFF=0
12 IP_TTL=128
13 IP_PROTO=17
14 IP_CHK=28497
15 IP_SRC=192.168.33.2
16 IP_DST=192.168.33.1
17
18 UDP_SRC=8304
19 UDP_DST=5060
20 UDP_LEN=726
21 UDP_CHK=12546
22
23 INVITE sip:[email protected] SIP/2.0
24 To: <sip:[email protected]>
25 From: TCC 200<sip:[email protected]>;tag=66064d22
26 Via: SIP/2.0/UDP 192.168.33.2:8304;branch=z9hG4bK-d87543-127761736-1--d87543-;rport
27 Call-ID: 4c15ae004b318627
28 CSeq: 1 INVITE
29 Contact: <sip:[email protected]:8304>
30 Max-Forwards: 70
31 Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
32 Content-Type: application/sdp
33 User-Agent: eyeBeam release 3004w stamp 16863
34 Content-Length: 235
35
36 v=0
37 o=- 56250259 56250343 IN IP4 192.168.33.2
80
38 s=eyeBeam
39 c=IN IP4 192.168.33.2
40 t=0 0
41 m=audio 8306 RTP/AVP 0 8 18 101
42 a=alt:1 1 : DCFAF33A 4E58F998 192.168.33.2 8306
43 a=fmtp:101 0-15
44 a=rtpmap:101 telephone-event/8000
45 a=sendrecv
Fonte: o autor, 2011.
Cada arquivo armazenado representa um pacote capturado efetuado pela seção
“Escuta”, ou um pacote capturado ou injetado efetuado pela seção “Injeção”. Cada arquivo
possui um padrão de armazenamento que identifica todas as partes do pacote incluindo a
sequência do pacote, dados dos cabeçalhos e dados do protocolo SIP.
Observando a Tabela 11, segue a descrição do padrão de arquivo utilizado para o
armazenamento dos dados capturados e/ou injetados:
“ARQ_NUM=” - identificação utilizada para armazenar a sequência do pacote.
“ETHER_MAC_SRC=” - identificação utilizada para armazenar o endereço MAC
de origem do pacote; a linha é finalizada com o caractere “;” para facilitar o resgate da
informação no momento da injeção.
“ETHER_MAC_DST=” - identificação utilizada para armazenar o endereço MAC
de destino do pacote; a linha é finalizada com o caractere “;” para facilitar o resgate da
informação no momento da injeção.
“ETHER_TYPE=” - identificação utilizada para armazenar o tipo de protocolo da
camada de inter-redes do pacote, no caso deste trabalho, apenas o protocolo IP será coletado
restringindo a identificação do protocolo ser sempre representada pelo número “8”.
“IP_VER=” - identificação utilizada para armazenar as informações de versão do
protocolo IP e o número de blocos de 32 bits que compõe o cabeçalho IP.
“IP_TOS=” - identificação utilizada para armazenar a informação do campo ToS do
cabeçalho IP.
“IP_LEN=” - identificação utilizada para armazenar a informação do tamanho do
pacote coletado incluindo o cabeçalho IP e demais camadas superiores.
“IP_ID=” - identificação utilizada para armazenar o campo de identificação do
cabeçalho IP.
“IP_OFF=” - identificação utilizada para armazenar o campo de offset do cabeçalho
IP.
81
“IP_TTL=” - identificação utilizada para armazenar o campo de “tempo de vida” do
cabeçalho IP.
“IP_PROTO=” - identificação utilizada para armazenar o campo de identificação de
protocolo da camada superior da camada IP; no caso deste trabalho, apenas o protocolo UDP
será coletado, restringindo a identificação do protocolo ser sempre representada pelo número
“17”.
“IP_CHK=” - identificação utilizada para armazenar o número de checksum do
cabeçalho IP do pacote coletado.
“IP_SRC=” - identificação utilizada para armazenar o endereço IP de origem do
pacote.
“IP_DST=” - identificação utilizada para armazenar o endereço IP de destino do
pacote.
“UDP_SRC=” - identificação utilizada para armazenar a porta de origem do
protocolo UDP.
“UDP_DST=” - identificação utilizada para armazenar a porta de destino do
protocolo UDP.
“UDP_LEN=” - identificação utilizada para armazenar a identificação do tamanho
do pacote coletado incluindo o cabeçalho UDP e os dados por ele transportado.
“UDP_CHK=” - identificação utilizada para armazenar o número de checksum do
cabeçalho UDP do pacote coletado.
A partir da linha 23, as informações armazenadas fazem parte do protocolo SIP que é
transportado pelo protocolo UDP.
3.4.2.2 Arquivo de Informações da Sessão
O arquivo de informações da sessão é utilizado para armazenar as informações da
sessão de captura efetuada na seção de escuta e na seção de injeção. Na Tabela 12 pode-se
observar um exemplo do arquivo de informações da sessão, os números à esquerda são apenas
identificadores das linhas do arquivo e não fazem parte do conteúdo.
82
Tabela 12 - Exemplo de arquivo de informação da sessão. 1 DEV=eth1
2 IP_ORIG=192.168.33.2
3 PORTA_DST=5060
4 ARQ_CAP_TOTAL=8
5 ARQ_RES_TOTAL=6
Fonte: o autor, 2011.
Observando a Tabela 12, segue descrição do padrão de armazenamento utilizado
para as informações da sessão:
“DEV=” - identificação utilizada para armazenar o nome do dispositivo utilizado na
captura e injeção dos pacotes.
“IP_ORIG=” - identificação utilizada para armazenar o endereço IP do dispositivo
monitorado pelo analisador SIP.
“PORTA_DST=” - identificação utilizada para armazenar a informação da porta de
destino ou origem do protocolo UDP.
“ARQ_CAP_TOTAL=” - identificação utilizada para armazenar o total de arquivos
capturados na sessão de captura efetuada dentro da seção “Escuta”.
“ARQ_RES_TOTAL=” - identificação utilizada para armazenar a informação do
total de arquivos injetados e capturados dentro da seção “Injeção”.
3.4.2.3 Arquivo de Informações dos Campos SIP
O arquivo de informações dos campos SIP armazena o valor original e o novo valor
dos campos do protocolo SIP. Na Tabela 13 pode-se observar um exemplo do arquivo de
informações dos campos SIP, os números à esquerda são apenas identificadores das linhas do
arquivo, não fazendo parte do seu conteúdo.
Tabela 13 - Exemplo de arquivo de informações dos campos SIP. 1 CALLER_ORIG=200
2 CALLED_ORIG=300
3 USERNAME_ORIG=200
4 CALLER=200
5 CALLED=500
6 USERNAME=200
7 PASSWORD=5678
Fonte: o autor, 2011.
Conforme observação efetuada na Tabela 13 segue descrição do padrão utilizado no
armazenamento das informações referentes aos campos do protocolo SIP:
83
“CALLER_ORIG=” - identificação utilizada para armazenar a informação original
do campo caller do protocolo SIP.
“CALLED_ORIG=” - identificação utilizada para armazenar a informação original
do campo called do protocolo SIP.
“USERNAME_ORIG=” - identificação utilizada para armazenar a informação
original do campo username do protocolo SIP.
“CALLER =” - identificação utilizada para armazenar o novo valor do campo caller
do protocolo SIP a ser atribuída no momento da injeção.
“CALLED =” - identificação utilizada para armazenar o novo valor do campo
called do protocolo SIP a ser atribuída no momento da injeção.
“USERNAME =” - identificação utilizada para armazenar o novo valor do campo
username do protocolo SIP a ser atribuída no momento da injeção.
“PASSWORD=” - identificação utilizada para armazenar a informação da senha do
usuário SIP que está sendo monitorado. Esse campo é apenas utilizado no momento da
injeção pelo tipo de mecanismo de autenticação utilizado no SIP.
3.4.3 Estrutura do Código
A estrutura de armazenamento do código fonte do software é a que segue:
main.c - arquivo de código responsável pela inicialização de todas as variáveis
globais do software e pelo controle de acesso às seções.
config.h - arquivo de cabeçalho onde todas as bibliotecas são adicionadas, todos os
arquivos de código devem adicionar este arquivo para ter acesso às bibliotecas.
varredura.h - arquivo de cabeçalho onde estão declaradas as funções de varredura
como por exemplo a localização de campos em arquivos de captura.
varredura.c - arquivo de código que desenvolve todas as funções de varredura como
por exemplo a localização de campos em arquivos de captura.
84
extract.h - arquivo que possui as funções de manipulação de organização de bits no
formato necessário para a criação dos pacotes.
pkt_header.h - arquivo de cabeçalho que possui a declaração das estruturas de dados
utilizados na captura e injeção dos pacotes.
print_pkt.h - arquivo de cabeçalho onde está declarada a função de impressão dos
dados do pacote na tela.
print_pkt.c - arquivo de código que desenvolve a função de impressão dos dados do
pacote na tela.
escuta.h - arquivo de cabeçalho que declara as funções utilizadas no controle da
seção “Escuta”.
escuta.c - arquivo de código que desenvolve as funções utilizadas no controle da
seção “Escuta”.
altera.h - arquivo de cabeçalho que declara as funções utilizadas no controle de
visualização dos dados escutados e alteração dos campos do protocolo SIP.
altera.c - arquivo de código que desenvolve as funções utilizadas no controle de
visualização dos dados escutados e alterações dos campos do protocolo SIP.
injection.h - arquivo de cabeçalho que declara as funções utilizadas no controle da
seção “Injeção”.
injection.c - arquivo de código que desenolve as funções utilizadas no controle da
seção “Injeção”.
cap.h - arquivo de cabeçalho que declara a função de processamento do pacote após
a sua captura.
cap.c - arquivo de código que desenvolve a função de processamento do pacote após
a sua captura.
menu.h - arquivo de cabeçalho que declara as funções de controle de menu.
menu.c - arquivo de código que desenvolve as funções de controle de menu.
checksum.h - arquivo de cabeçalho que declara a função de geração do número de
checksum dos cabeçalhos IP e UDP.
85
checksum.c - arquivo de código que desenvolve a função de geração do número de
checksum dos cabeçalhos IP e UDP.
md5.h - arquivo de cabeçalho que declara as funções envolvidas na autenticação
MD5 utilizada no protocolo SIP.
md5.c - arquivo de código que desenvolve as funções envolvidas na autenticação
MD5 utilizada no protocolo SIP.
tty_set.h - arquivo de cabeçalho que declara a função de manipulação do modo de
entrada de dados no terminal.
tty_set.c - arquivo de código que desenvolve a função de manipulação do modo de
entrada de dados no terminal.
3.4.4 Declaração das Bibliotecas e Variáveis Globais
O arquivo de cabeçalho config.h descreve a declaração das bibliotecas e das variáveis
globais utilizadas. Na Tabela 14 pode-se observar a descrição completa do arquivo, os
números visualizados à esquerda são apenas identificadores das linhas do arquivo e não fazem
parte do código.
Tabela 14 - Arquivo de cabeçalho config.h. 1 #ifndef CONFIG_H_
2 #define CONFIG_H_
3
4 char *dev;
5 char *ip_orig;
6 char *porta_dst;
7 char *arq_info_nome;
8 char *arq_cap_nome;
9 char *arq_res_nome;
10 char *arq_pcap_nome;
11 char *arq_data_nome;
12 int *arq_cap_cnt;
13 int *arq_res_cnt;
14 int *arq_pcap_cnt;
15 char *arq_cap_local;
16 char *int_arq;
17 int *stop_thread;
18 char *sip_caller;
19 char *sip_callern;
20 char *sip_called;
21 char *sip_calledn;
22 char *sip_username;
23 char *sip_usernamen;
24 char *sip_password;
25 char *sip_passwordn;
26
27 #include <stdio.h>
28 #include <stdlib.h>
86
29 #include <stdio_ext.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <termios.h>
33 #include <pthread.h>
34
35 #include "pkt_header.h"
36 #include "extract.h"
37 #include "checksum.h"
38 #include "md5.h"
39 #include "varredura.h"
40 #include "tty_set.h"
41
42 #include <pcap.h>
43 #include <netinet/if_ether.h>
44 #include <netinet/ip.h>
45 #include <arpa/inet.h>
46
47 #include <netdb.h>
48 #include <netinet/in.h>
49 #include <sys/socket.h>
50
51 #endif /* CONFIG_H_ */
Fonte: o autor, 2011.
As variáreis globais utilizadas são ponteiros do tipo char10
e int11
. Os ponteiros são:
dev - ponteiro utilizado para armazenar o nome da interface utilizada na captura e
injeção dos pacotes.
ip_orig - ponteiro utilizado para armazenar o endereço IP do dispositivo monitorado.
porta_dst - ponteiro utilizado para armazenar a porta de origem e destino UDP dos
pacotes a serem capturados.
arq_info_nome - ponteiro utilizado para armazenar o nome do arquivo que possui as
informações da sessão.
arq_cap_nome - ponteiro utilizado para armazenar parte do nome dos arquivos de
captura.
arq_data_nome - ponteiro utilizado para armazenar o nome do arquivo das
informações dos campos SIP.
arq_pcap_nome - ponteiro utilizado para apontar o nome de arquivo a ser utilizado
na função de processamento de pacotes callback.
arq_cap_local - ponteiro utilizado para armazenar o caminho onde os arquivos de
captura e informações são armazenados.
10
Char pode ser definido como um tipo de variável que ocupa o espaço de 1 byte na memória (CPLUSPLUS,
2011). 11
Int pode ser definido como um tipo de variável que ocupa o espaço de 4 bytes na memória e armazena um
número inteiro (CPLUSPLUS, 2011).
87
arq_cap_cnt - ponteiro utilizado para armazenar o número de pacotes capturados
pela sessão de captura efetuada na seção “Escuta”.
arq_res_cnt - ponteiro utilizado para armazenar o número de pacotes capturados pela
sessão de captura e injeção efetuadas na seção “Injeção”.
arq_pcap_cnt - ponteiro utilizado para apontar o número de pacotes capturados
utilizados na função de processamento de pacotes callback.
int_arq - ponteiro utilizado para manipulação do número de pacotes capturados em
formato char.
stop_thread - ponteiro utilizado para controle de execução de uma thread12
.
sip_caller - ponteiro utilizado para armazenamento do valor original do campo caller
do protocolo SIP.
sip_callern - ponteiro utilizado para armazenamento do novo valor do campo caller
do protocolo SIP.
sip_called - ponteiro utilizado para armazenamento do valor original do campo
called do protocolo SIP.
sip_calledn - ponteiro utilizado para armazenamento do novo valor do campo called
do protocolo SIP.
sip_username - ponteiro utilizado para armazenamento do valor original do campo
username do protocolo SIP.
sip_usernamen - ponteiro utilizado para armazenamento do novo valor do campo
username do protocolo SIP.
sip_passwordn - ponteiro utilizado para armazenamento do valor do campo
password do protocolo SIP.
Pode-se identificar as bibliotecas utilizadas: stdio.h, stdlib.h, stdio_ext.h, unistd.h,
string.h, termios.h, pthread.h, pcap.h, if_ether.h, ip.h, inet.h, netdb.h, in.h e socket.h.
Pode-se identificar também os arquivos de cabeçalhos de uso geral: pkt_header.h,
extract.h, checksum.h, md5.h, varredura.h e tty_set.h.
12
Uma thread pode ser definida como uma forma de execução paralela dentro de um mesmo software
(CPLUSPLUS, 2011).
88
Demais arquivos de cabeçalho contidos na estrutura de arquivos do software não
declarados neste arquivo, são referenciados individualmente nos arquivos de código.
3.4.5 Estruturas de Cabeçalho
A estrutura de cabeçalho consiste em uma estrutura de dados onde os cabeçalhos dos
pacotes capturados são conformados (CASADO, 2001). Através desta conformação, é
possível separar todos os campos dos cabeçalhos Ethernet, IP, UDP e pseudo-header. As
estruturas de cabeçalho são declaradas no arquivo pkt_header.h.
A estrutura do cabeçalho Ethernet é formada por três variáveis: o endereço MAC de
origem, o endereço MAC de destino e o tipo de protocolo da camada superior. Na Tabela 15 é
mostrada a declaração da estrutura do cabeçalho Ethernet.
Tabela 15 - Estrutura do cabeçalho Ethernet. 9 struct sniff_ethernet {
10 u_int8_t ether_dhost[ETHER_ADDR_LEN];
11 u_int8_t ether_shost[ETHER_ADDR_LEN];
12 u_int16_t ether_type;
13 };
Fonte: o autor, 2011.
A estrutura do cabeçalho IP é formada por dez variáveis: versão do protocolo IP,
campo ToS, tamanho, campo id, campo offset, campo ttl, protocolo da camada superior,
checksum, endereço IP de origem e endereço IP de destino. Na Tabela 16 pode-se observar a
declaração da estrutura do cabeçalho IP.
Tabela 16 - Estrutura do cabeçalho IP. 15 struct sniff_ip {
16 u_char ip_vhl;
17 u_char ip_tos;
18 u_short ip_len;
19 u_short ip_id;
20 u_short ip_off;
21 #define IP_RF 0x8000
22 #define IP_DF 0x4000
23 #define IP_MF 0x2000
24 #define IP_OFFMASK 0x1fff
25 u_char ip_ttl;
26 u_char ip_p;
27 u_short ip_sum;
28 struct in_addr ip_src,ip_dst;
29 };
Fonte: o autor, 2011.
A estrutura do cabeçalho UDP é formada por quatro variáveis: porta de origem, porta
de destino, tamanho e checksum. Na Tabela 17 pode-se observar a declaração da estrutura do
cabeçalho UDP.
89
Tabela 17 - Estrutura do cabeçalho UDP. 32 struct sniff_udp {
33 u_short uh_sport;
34 u_short uh_dport;
35 u_short uh_ulen;
36 u_short uh_sum;
37 };
Fonte: o autor, 2011.
O pseudo-header utilizado para a geração do checksum também foi conformado
através de uma estrutura que possui os campos: endereço IP de origem, endereço IP de
destino, campo zerado, protocolo da camada de transporte e campo tamanho do protocolo
UDP. Na Tabela 18 pode ser observada a declaração da estrutura do pseudo-header.
Tabela 18 - Estrutura do pseudo-header. 40 struct pseudo_header {
41 u_int32_t ip_src;
42 u_int32_t ip_dst;
43 u_char zero1;
44 u_char proto;
45 u_int16_t udp_len;
46 };
Fonte: o autor, 2011.
3.4.6 Funções Globais
Como funções globais podemos citar as que são desenvolvidas nos arquivos:
varredura.c, extract.h, print_pkt.c, cap.c, tty_set.c, md5.c e checksum.c.
As funções contidas nos arquivos checksum.c, md5.c e extract.h não estão detalhadas
neste trabalho pois foram apenas adicionadas ao projeto e não desenvolvidas. Estas funções
podem ser observadas nos ANEXOS A, B e C respectivamente.
3.4.6.1 Função valor_string
A função valor_string é desenvolvida no arquivo varredura.c e é utilizada para
retornar o valor dos campos que identificam os dados dos pacotes capturados e os dados dos
campos SIP. A Tabela 19 mostra o desenvolvimento da função. Os números que aparecem à
esquerda não fazem parte do código, apenas identificam as linhas do aquivo.
90
Tabela 19 - Desenvolvimento da função valor_string. 7 int valor_string(FILE *my_stream,char *str_to_find, char *ptr_rec, char end_char, char
exc_char)
8 {
9 char buffer[300];
10 char val[300];
11 char *buff_ptr, *find_ptr;
12 int i,j,len,saida;
13 len = strlen(str_to_find);
14 memset(&buffer,0,sizeof(char)*300);
15 memset(&val,0,sizeof(char)*300);
16 i = 0;
17 j = 0;
18 saida = 0;
19
20 rewind(my_stream);
21 while (fgets(buffer,300,my_stream)) {
22 buff_ptr = buffer;
23 if ((find_ptr = strstr(buff_ptr,str_to_find))) {
24 saida = 1;
25 find_ptr += len;
26 while(*find_ptr != end_char && *find_ptr != EOF)
27 if (*find_ptr != exc_char)
28 val[i++]=*find_ptr++;
29 else
30 find_ptr++;
31 }
32 }
33 if (i > 0)
34 val[i++] = '\0';
35 memcpy(ptr_rec,val,i);
36 return(saida);
37 }
Fonte: o autor, 2011.
A função deve encontrar no stream13
denominado como my_stream o campo
identificado pelo ponteiro str_to_find, armazenar individualmente os caracteres diferentes do
caractere identificado pela variável exc_char em uma variável de apoio até encontrar o
caractere identificado na variável end_char. Quando encontrar o caractere que finaliza o valor
do campo, os dados são copiados da variável de apoio para o ponteiro ptr_rec. A função
retorna “1” se o campo procurado foi encontrado e “0” se o campo procurado não foi
encontrado.
3.4.6.2 Função troca_string
A função troca_string é desenvolvida no arquivo varredura.c e é utilizada para
efetuar a troca de valores de campos dentro de um arquivo. Na Tabela 20 pode-se observar o
desenvolvimento da função, os números à esquerda são apenas identificadores das linhas no
arquivo e não fazem parte do código de desenvolvimento da função.
13
Stream pode ser definido como um bloco de dados que representa um arquivo (WALL, WATSON e WHITIS,
1999).
91
Tabela 20 - Desenvolvimento da função troca_string. 40 int troca_string(char *file_name, char *str_to_find, char *str_to_change)
41 {
42 FILE *my_stream,*temp_stream;
43 char temp_name[50];
44 char comando[150];
45 char line_buff[300],str2find_buff[50],str2change_buff[50];
46 char *new_line_buff;
47 char ini_buff[200],end_buff[200];
48 char *line_ptr, *find_ptr, *aft_find_ptr;
49 int len_line,len_str2find,len_str2change,trocaok,i;
50 fpos_t posit;
51
52 new_line_buff = (char *)malloc(sizeof(char)*300);
53 memset(&temp_name,'\0',sizeof(char)*50);
54 memset(&comando,'\0',sizeof(char)*150);
55 memset(&line_buff,'\0',sizeof(char)*300);
56 memset(&str2find_buff,'\0',sizeof(char)*50);
57 memset(&str2change_buff,'\0',sizeof(char)*50);
58 len_str2find = 0;
59 len_str2change = 0;
60 trocaok = 0;
61
62 sprintf(temp_name,"%s_temp",file_name);
63 temp_stream = fopen(temp_name,"w");
64 sprintf(str2find_buff,"%s",str_to_find);
65 sprintf(str2change_buff,"%s",str_to_change);
66 len_str2find = strlen(str2find_buff);
67 len_str2change = strlen(str2change_buff);
68
69 if ((my_stream = fopen(file_name,"r"))){
70 rewind(my_stream);
71 while (fgets(line_buff,300,my_stream)) {
72 memset(new_line_buff,'\0',sizeof(char)*300);
73 fgetpos(my_stream,&posit);
74 line_ptr = line_buff;
75 len_line = strlen(line_buff);
76 if ((find_ptr = strstr(line_ptr,str_to_find))) {
77 aft_find_ptr = find_ptr + len_str2find;
78 memset(&ini_buff,'\0',sizeof(char)*200);
79 memset(&end_buff,'\0',sizeof(char)*200);
80 i = 0;
81 while (line_ptr != find_ptr) {
82 ini_buff[i++] = *line_ptr++;
83 };
84 i = 0;
85 while (*aft_find_ptr != '\n') {
86 end_buff[i++] = *aft_find_ptr++;
87 };
88 memcpy(new_line_buff,ini_buff,strlen(ini_buff));
89 memcpy(new_line_buff+strlen(ini_buff),str2change_buff,\
90 strlen(str2change_buff));
91
memcpy(new_line_buff+strlen(ini_buff)+strlen(str2change_buff),\
92 end_buff,strlen(end_buff));
93 fprintf(temp_stream,"%s\n",new_line_buff);
94 trocaok = trocaok + 1;
95 } else {
96 fprintf(temp_stream,"%s",line_buff);
97 }
98 }
99 fclose(my_stream);
100 }
101 fclose(temp_stream);
102 sprintf(comando,"mv -f %s %s",temp_name,file_name);
103 system(comando);
104 return(trocaok);
105 }
Fonte: o autor, 2011.
Esta função deve abrir o arquivo identificado pelo argumento file_name, encontrar a
sequência de caracteres armazenada em str_to_find e substituir pela sequência de caracteres
armazenada em str_to_change.A função retorna um número inteiro de quantas vezes a troca
92
foi efetuada no arquivo. O processo de troca utiliza a criação de um arquivo temporário onde
são gravados os dados do arquivo original com a troca efetuada, depois disso o arquivo
original é apagado e o arquivo temporário é renomeado para o arquivo original.
3.4.6.3 Função metodo_sip
A função metodo_sip é desenvolvida no arquivo varredura.c, é utilizada para
identificar o método utilizado pelo protocolo SIP no stream passado como argumento. A
Tabela 21 mostra o desenvolvimento da função. Os números visualizados à esquerda não
fazem parte do código, apenas identificam as linhas no arquivo.
Tabela 21 - Desenvolvimento da função metodo_sip. 108 void metodo_sip(FILE *my_stream, char *ptr_rec)
109 {
110 char buffer[300];
111 char ch;
112 int i,k;
113 fpos_t positn,positr;
114 memset(&buffer,0,sizeof(char)*300);
115 i = 0;
116 k = 0;
117
118 rewind(my_stream);
119 do {
120 ch = fgetc(my_stream);
121 if (ch == '\n') {
122 fgetpos(my_stream,&positn);
123 k++;
124 }
125 } while (ch != '\r');
126 fgetpos(my_stream,&positr);
127 i = positr.__pos - positn.__pos;
128 fsetpos(my_stream,&positn);
129 fgets(ptr_rec,i,my_stream);
130 }
Fonte: o autor, 2011.
3.4.6.4 Função valor_sip_string
A função valor_sip_string é desenvolvida no arquivo varredura.c, é baseada na
função valor_string descrita na seção 3.4.6.1. A diferença está no ponteiro do tipo char
denominado start_line que é passado para a função valor_sip_string. O processo é semelhante
a função valor_string, a diferença é que esta função localiza apenas o valor da variável cuja
93
linha do bloco de dados do protocolo SIP inicia com os caracteres identificados pelo ponteiro
start_line. A função retorna “1” se encontrar o valor procurado e “0” se não encontrar. A
Tabela 22 mostra o desenvolvimento da função, os números visualizados à esquerda da figura
são apenas identificadores das linhas do arquivo não fazendo parte do código.
Tabela 22 - Desenvolvimento da função valor_sip_string. 133 int valor_sip_string(FILE *my_stream, char *start_line, char *str_to_find,\
134 char *ptr_rec, char end_char, char exc_char)
135 {
136 char buffer[300];
137 char val[300];
138 char *buff_ptr, *find_ptr;
139 int i,j,k,len,saida;
140 len = strlen(str_to_find);
141 memset(&buffer,'\0',sizeof(char)*300);
142 memset(&val,'\0',sizeof(char)*300);
143 i = 0;
144 j = 0;
145 k = 0;
146
147 rewind(my_stream);
148 while (fgets(buffer,300,my_stream)) {
149 buff_ptr = buffer;
150 if ((find_ptr = strstr(buff_ptr,start_line))) {
151 if ((find_ptr = strstr(buff_ptr,str_to_find))) {
152 saida = 1;
153 find_ptr += len;
154 while(*find_ptr != end_char && *find_ptr != EOF)
155 if (*find_ptr != exc_char)
156 val[i++]=*find_ptr++;
157 else
158 find_ptr++;
159 }
160 }
161 }
162 if (i > 0)
163 val[i++] = '\0';
164 memcpy(ptr_rec,val,i);
165 return(saida);
166 }
Fonte: o autor, 2011.
3.4.6.5 Função payload_sip
A função payload_sip é desenvolvida no arquivo varredura.c, é utilizada para obter
todo o conteúdo do protocolo SIP armazenado em um arquivo de captura. A Tabela 23 mostra
o desenvolvimento da função. Os números visualizados à esquerda da figura são apenas
indentificadores das linhas e não fazem parte do código.
Tabela 23 - Desenvolvimento da função payload_sip. 169 void payload_sip(FILE *my_stream,int *i,fpos_t *j)
170 {
171 char ch;
172 fpos_t positn,positr;
173
174 *i = 0;
175
94
176 rewind(my_stream);
177 do {
178 ch = fgetc(my_stream);
179 if (ch == '\n') {
180 fgetpos(my_stream,&positn);
181 }
182 } while (ch != '\r');
183 //positn.__pos++;
184 fsetpos(my_stream,&positn);
185 do {
186 ch = fgetc(my_stream);
187 } while (ch != EOF);
188 fgetpos(my_stream,&positr);
189 *i = positr.__pos - positn.__pos;
190 memcpy(j,&positn,sizeof(fpos_t));
191 }
Fonte: o autor, 2011.
A função varre o stream passado como argumento, localiza o início do bloco de
dados SIP, o seu tamanho, grava ambos os dados nos demais argumentos passados e finaliza.
Com esses dados a função que executou a função payload_sip faz a leitura dos dados no
arquivo.
3.4.6.6 Função str2hex
A função str2hex é desenvolvida no arquivo varredura.c, é utilizada para converter
uma string14
de dois caracteres em um número hexadecimal. O processo consiste na
comparação de cada caractere da string com todos os possíveis caracteres da base
hexadecimal e assim montar o número hexadecimal. O retorno da função é o próprio número
hexadecimal convertido. A Tabela 24 mostra parte do desenvolvimento da função. Os
números à esquerda são utilizados apenas para identificar as linhas do arquivo e não fazem
parte do código.
Tabela 24 - Parte do desenvolvimento da função str2hex. 194 u_int8_t str2hex(char *str_ary)
195 {
196 u_int8_t saida;
197 char str[3];
198 char ch;
199 memcpy(&str,str_ary,sizeof(char)*3);
200 if ((str[1] == '\0')) {
201 str[2] = '\0';
202 ch = str[0];
203 str[1] = ch;
204 str[0] = '0';
205 }
206 if (str[0] == '0') {
207 if (str[1] == '0')
208 saida = 0x00;
209 else if (str[1] == '1')
210 saida = 0x01;
14
String pode ser definido como um vetor de variáveis do tipo char (CPLUSPLUS, 2011).
95
211 else if (str[1] == '2')
212 saida = 0x02;
213 else if (str[1] == '3')
214 saida = 0x03;
215 else if (str[1] == '4')
216 saida = 0x04;
217 else if (str[1] == '5')
218 saida = 0x05;
219 else if (str[1] == '6')
220 saida = 0x06;
221 else if (str[1] == '7')
222 saida = 0x07;
223 else if (str[1] == '8')
224 saida = 0x08;
225 else if (str[1] == '9')
226 saida = 0x09;
227 else if ((str[1] == 'a') || (str[1] == 'A'))
228 saida = 0x0a;
229 else if ((str[1] == 'b') || (str[1] == 'B'))
230 saida = 0x0b;
231 else if ((str[1] == 'c') || (str[1] == 'C'))
232 saida = 0x0c;
233 else if ((str[1] == 'd') || (str[1] == 'D'))
234 saida = 0x0d;
235 else if ((str[1] == 'e') || (str[1] == 'E'))
236 saida = 0x0e;
237 else if ((str[1] == 'f') || (str[1] == 'F'))
238 saida = 0x0f;
239 } else if (str[0] == '1') {
Fonte: o autor, 2011.
3.4.6.7 Função imprime_pkt
A função imprime_pkt é desenvolvida no arquivo print_pkt.c, é utilizada para gerar a
impressão dos dados do arquivo de captura em um formato padrão na tela do operador do
software. O processo consiste na abertura do arquivo passado como argumento e varredura
em busca das informações de: sequência de captura, endereço IP de origem, endereço IP de
destino, porta UDP de origem, porta UDP de destino e método SIP. Depois disso é efetuada a
impressão das informações na tela do operador. A Tabela 25 mostra o desenvolvimento da
função. Os números observados na figura são apenas para identificar as linhas do arquivo não
fazendo parte do código.
Tabela 25 - Desenvolvimento da função imprime_pkt. 1 #include "config.h"
2 #include "menu.h"
3
4 void imprime_pkt(char *pathname)
5 {
6 FILE *arq_data = NULL;
7
8 char arqnum[5];
9 char srcip[30];
10 char dstip[30];
11 char udpsrc[10];
12 char udpdst[10];
13 char header[100];
14
96
15 arq_data = fopen(pathname,"r");
16
17 valor_string(arq_data,"ARQ_NUM=",arqnum,'\n','\0');
18 valor_string(arq_data,"IP_SRC=",srcip,'\n','\0');
19 valor_string(arq_data,"IP_DST=",dstip,'\n','\0');
20 valor_string(arq_data,"UDP_SRC=",udpsrc,'\n','\0');
21 valor_string(arq_data,"UDP_DST=",udpdst,'\n','\0');
22 metodo_sip(arq_data,header);
23
24 fclose(arq_data);
25 if (strcmp(srcip,ip_orig) == 0)
26 printf("\t%s %s:%s\t\t---->\t\t%s:%s
\t%s\n",arqnum,srcip,udpsrc,dstip,udpdst,header);
27 else
28 printf("\t%s %s:%s\t\t<----\t\t%s:%s
\t%s\n",arqnum,dstip,udpdst,srcip,udpsrc,header);
29 }
Fonte: o autor, 2011.
Na Figura 52 pode-se visualizar o formato de impressão realizado pela função
imprime_pkt com todas as informações mencionadas.
Figura 52 - Exemplo de impressão realizada pela função imprime_pkt. Fonte: o autor, 2011.
3.4.6.8 Função rl_ttyset
A função rl_ttyset é desenvolvida no arquivo tty_set.c, é utilizada para alterar o modo
padrão de entrada de dados no terminal onde a interface com o operador é apresentada. A
Tabela 26 mostra o desenvolvimento da função. Os números à esquerda da figura são
utilizados apenas para identificar as linhas do arquivo e não fazem parte do código.
Tabela 26 - Desenvolvimento da função rl_ttyset. 1 #include <termios.h>
2
3 void rl_ttyset(int reset)
4 {
5 static struct termios old_conf; // Armazena as configuracoes antigas
6 struct termios new_conf; // Recebe as novas configuracoes
7
8 if (reset == 0) {
9 (void) tcgetattr (0, &old_conf);
10 new_conf = old_conf; // Copia as configuracoes antigas
11 new_conf.c_lflag &= ~(ECHO | ICANON);
12 new_conf.c_iflag &= ~(ISTRIP | INPCK);
13 (void) tcsetattr (0, TCSANOW, &new_conf); // Habilita as novas configuracoes
14 } else
15 (void) tcsetattr (0, TCSANOW, &old_conf); // Restaura as configuracoes antigas
16 }
Fonte: o autor, 2011.
97
O processo consiste em modificar duas flags15
ou restaurar a configuração anterior
do terminal para permitir que o usuário entre com dados através do teclado sem a confirmação
de entrada pela tecla Enter.
3.4.6.9 Função callback
A função callback é desenvolvida no arquivo cap.c, é utilizada durante uma sessão
de captura para efetuar o processamento dos pacotes capturados. Esta função é executada pela
função pcap_dispatch da libpcap que é responsável pela captura dos pacotes.
Inicialmente a função declara e inicializa as variáveis necessárias como pode ser
observado na Tabela 27, os números visualizados à esquerda são apenas identificadores das
linhas do arquivo não fazendo parte do código.
Tabela 27 - Início da função callback. 5 void callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* packet)
6 {
7 char file_num[5];
8 char sip_fhdr[100];
9 char pathname[20];
10
11 const struct sniff_ethernet *ethernet;
12 const struct sniff_ip *ip;
13 const struct sniff_udp *udp;
14
15 const u_char *payload;
16
17 u_int size_ip;
18 u_int size_udp;
19
20 FILE *arq = NULL;
21
22 char srcip[100];
23 char dstip[100];
24 u_int16_t srcudp;
25 u_int16_t dstudp;
26
27 char hdr_sip[1000];
28 char aux1,aux2;
29
30 int j,k;
31
32 memset(&sip_fhdr,0,sizeof(char)*100);
33 memset(&file_num,0,sizeof(char)*5);
Fonte: o autor, 2011.
Continuando com o desenvolvimento da função callback na Tabela 28, o segundo
passo é a configuração do nome e criação do arquivo que vai armazenar os dados do pacote
nas linhas 35 a 40. Depois é feita a conformação do pacote na estrutura do cabeçalho
15
Uma flag pode ser definida como uma opção a ser configurada com valores pré-definidos.
98
Ethernet, o início da extração dos campos do cabeçalho e a gravação desses campos no
arquivo criado. Os números visualizados à esqueda apenas identificam as linhas, não fazem
parte do código.
Tabela 28 - Primeira parte do desenvolvimento da função callback. 35 if (*arq_pcap_cnt < 10)
36 sprintf(file_num,"0%d",*arq_pcap_cnt);
37 else
38 sprintf(file_num,"%d",*arq_pcap_cnt);
39 sprintf(pathname,"%s%s.cap",arq_pcap_nome,file_num);
40 arq = fopen(pathname,"w");
41
42 fprintf(arq,"ARQ_NUM=%s\n\n",file_num);
43
44 ethernet = (struct sniff_ethernet*)packet;
45
46 aux1 = '=';
47 aux2 = ':';
48 j = ETHER_ADDR_LEN;
49 fprintf(arq,"ETHER_MAC_SRC");
50 do{
51 fprintf(arq,"%c%X",(j == ETHER_ADDR_LEN) ? aux1 : aux2,ethernet-
>ether_shost[6-j]);
52 }while(--j>0);
53 fprintf(arq,";");
54
55 j = ETHER_ADDR_LEN;
56 fprintf(arq,"\nETHER_MAC_DST");
57 do{
58 fprintf(arq,"%c%X",(j == ETHER_ADDR_LEN) ? aux1 : aux2,ethernet-
>ether_dhost[6-j]);
59 }while(--j>0);
60 fprintf(arq,";");
61
62 fprintf(arq,"\nETHER_TYPE=%u\n\n",ethernet->ether_type);
Fonte: o autor, 2011.
Na Tabela 29 inicia o processo de conformação do pacote na estrutura do cabeçalho
IP e UDP, extraindo todos os campos de cada cabeçalho e gravando esses dados no arquivo de
armazenamento. Depois disso é feita a leitura do payload16
do pacote que corresponde ao
bloco de dados do protocolo SIP, e a gravação desses dados no arquivo de armazenamento.
Os números visualizados à esquerda são apenas identificadores das linhas do arquivo não
fazendo parte do código.
Tabela 29 – Segunda parte do desenvolvimento da função callback. 65 if (ethernet->ether_type == 0x0008) {
66 ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
67 size_ip = IP_HL(ip)*4;
68 inet_ntop(AF_INET, &ip->ip_src, srcip, sizeof(srcip));
69 inet_ntop(AF_INET, &ip->ip_dst, dstip, sizeof(dstip));
70
71 fprintf(arq,"IP_VER=%u\n",ip->ip_vhl);
72 fprintf(arq,"IP_TOS=%u\n",ip->ip_tos);
73 fprintf(arq,"IP_LEN=%u\n",EXTRACT_16BITS(&ip->ip_len));
74 fprintf(arq,"IP_ID=%u\n",EXTRACT_16BITS(&ip->ip_id));
75 fprintf(arq,"IP_OFF=%u\n",ip->ip_off);
76 fprintf(arq,"IP_TTL=%u\n",ip->ip_ttl);
77 fprintf(arq,"IP_PROTO=%u\n",ip->ip_p);
78 fprintf(arq,"IP_CHK=%u\n",EXTRACT_16BITS(&ip->ip_sum));
79 fprintf(arq,"IP_SRC=%s\n",srcip);
80 fprintf(arq,"IP_DST=%s\n\n",dstip);
81
16
Payload pode ser definido como a carga de dados transportada pelo pacote (TANENBAUM, 2003).
99
82 if (ip->ip_p == 17) {
83 udp = (struct sniff_udp*)(packet + SIZE_ETHERNET + size_ip);
84 srcudp = ntohs(udp->uh_sport);
85 dstudp = ntohs(udp->uh_dport);
86
87 fprintf(arq,"UDP_SRC=%d\n",srcudp);
88 fprintf(arq,"UDP_DST=%d\n",dstudp);
89 fprintf(arq,"UDP_LEN=%u\n",EXTRACT_16BITS(&udp->uh_ulen));
90 fprintf(arq,"UDP_CHK=%u\n\n",EXTRACT_16BITS(&udp->uh_sum));
91
92 size_udp = 8;
93 payload=(u_char *)malloc(EXTRACT_16BITS(&udp-
>uh_ulen)*sizeof(u_char));
94 payload = (u_char *)(packet + SIZE_ETHERNET + size_ip +
size_udp);
95 fprintf(arq,"%s",payload);
96 fclose(arq);
97
98 sprintf(hdr_sip,"%s",payload);
Fonte: o autor, 2011.
Na Tabela 30 é efetuado o último processo da função callback, a impressão dos
dados do pacote na tela de captura da seção “Escuta”. No caso da função callback, a
impressão dos dados é efetuada diretamente ao invés de utilizar a função imprime_pkt. Foi
definido desta forma pelo fato da função imprime_pkt abrir o arquivo de captura, ler os dados
e fechar o arquivo, sendo que neste ponto da função callback todos os dados já estão
armazenados em variáveis tornando mais rápido o acesso a eles e diminuindo assim o
processamento.
Tabela 30 - Terceira parte do desenvolvimento da função callback. 99 k = 0;
100 j = 0;
101 do {
102 if (hdr_sip[k] != 0x0a)
103 sip_fhdr[j++] = hdr_sip[k];
104 else
105 break;
106 k++;
107 } while (1);
108
109 if (k > 5) {
110 if (strcmp(srcip,ip_orig) == 0)
111 printf("\t%s %s:%u\t\t---->\t\t%s:%u
\t%s\n",file_num,srcip,srcudp,dstip,dstudp,sip_fhdr);
112 else
113 printf("\t%s %s:%u\t\t<----\t\t%s:%u
\t%s\n",file_num,dstip,dstudp,srcip,srcudp,sip_fhdr);
114 *arq_pcap_cnt = *arq_pcap_cnt + 1;
115
116 if (arq_pcap_cnt == arq_res_cnt) {
117 *stop_thread = 1;
118 }
119 } else
120 remove(pathname);
121 }
122 }
123 }
Fonte: o autor, 2011.
100
3.4.7 Controle de Menu
O controle de menu do software é feito pelo código contido no arquivo menu.c.
Basicamente os controles de menu são responsáveis pela impressão do menu na tela do
operador e pela leitura de entrada de teclado, algumas funções possuem ainda alguns
controles específicos descritos a seguir.
3.4.7.1 Função cabecalho
A função cabecalho é utilizada para imprimir o cabeçalho das telas do software. Esta
função recebe dois argumentos que complementam a impressão da tela de cada seção. A
Tabela 31 mostra o desenvolvimento da função cabecalho. Os números visualizados à
esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 31 - Desenvolvimento da função cabecalho. 4 void cabecalho(char *arg1, char *arg2)
5 {
6 system("clear");
7 printf("\n");
8 printf("\t############################################################\n");
9 printf("\t### ANALISADOR SIP ###\n");
10 printf("\t############################################################\n\n");
11 printf("\t###\t%s\n\n\t%s\n\n\n",arg1,arg2);
12 }
Fonte: o autor, 2011.
3.4.7.2 Função menu_main
A função menu_main é utilizada para imprimir o menu principal na tela do operador
e para efetuar a leitura de teclado que define qual seção o operador deseja acessar. A leitura é
efetuada, processada de acordo com as opções disponíveis para acesso, repetindo a função
caso a opção do operador for considerada inválida, depois a opção é repassada como retorno
da função. A Tabela 32 mostra o desenvolvimento da função menu_main. Os números
visualizados à esquerda são apenas identificadores das linhas, não fazendo parte do código.
101
Tabela 32 - Desenvolvimento da função menu_main. 14 char menu_main()
15 {
16 char opt;
17 int saida;
18 do {
19 cabecalho("MENU PRINCIPAL","");
20 printf("\t\t1 - Escuta\n");
21 printf("\t\t2 - Dados Escutados\n");
22 printf("\t\t3 - Injeção\n");
23 printf("\t\t4 - Mostra Resultados\n");
24 printf("\t\t5 - Limpar Resultados\n");
25 printf("\t\t6 - Limpar Tudo\n");
26 printf("\t\n\n");
27 printf("\t\tDigite a opção ou 'q' para sair: ");
28
29 opt = getchar();
30 if ((opt != '1') && (opt != '2') && (opt != '3') && (opt != '4') \
31 && (opt != '5') && (opt != '6') && (opt != 'q')) {
32 printf("\n\t\tOpção inválida!");
33 __fpurge(stdin);
34 getchar();
35 saida = 0;
36 printf("\n");
37 } else {
38 __fpurge(stdin);
39 saida = 1;
40 }
41 } while (saida != 1);
42
43 return opt;
44 }
Fonte: o autor, 2011.
Nota-se o uso do comando __fpurge(stdin) antes do comando getchar(), esse
comando foi utilizado para fazer a limpeza do buffer17
de teclado para garantir que o software
receba apenas o que o usuário digitar.
3.4.7.3 Função menu_1
A função menu_1 é utilizada para imprimir o menu da seção “Escuta” na tela do
operador e efetuar a leitura de teclado que identifica a opção do operador dentro desta seção.
A Tabela 33 mostra o desenvolvimento da função menu_1. Os números visualizados à
esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 33 - Desenvolvimento da função menu_1. 46 char menu_1()
47 {
48 char opt;
49 int saida;
50
51 do {
52 cabecalho("MENU PRINCIPAL >>> 1-ESCUTA","");
53 printf("\t\t1 - Interface (%s)\n",dev);
17
Buffer pode ser definido como uma memória de armazenamento temporário (WALL, WATSON e WHITIS,
1999).
102
54 printf("\t\t2 - IP Origem (%s)\n",ip_orig);
55 printf("\t\t3 - Porta Destino (%s)\n",porta_dst);
56 printf("\t\t4 - Iniciar Escuta\n");
57 printf("\n\n");
58 printf("\t\tDigite a opção ou 'q' para voltar: ");
59
60 opt = getchar();
61 if ((opt != '1') && (opt != '2') && (opt != '3') && \
62 (opt != '4') && (opt != 'q')) {
63 printf("\n\t\tOpção inválida!");
64 __fpurge(stdin);
65 getchar();
66 saida = 0;
67 printf("\n");
68 } else {
69 __fpurge(stdin);
70 saida = 1;
71 }
72 } while (saida != 1);
73 return opt;
74 }
Fonte: o autor, 2011.
3.4.7.4 Função menu_1_1
A função menu_1_1 é utilizada para impressão do menu de configuração da interface
de captura na tela do operador e para efetuar a leitura da interface de captura. A leitura do
nome da interface é efetuada, a interface é testada e se ela estiver disponível é gravada na
variável dev. A Tabela 34 mostra o desenvolvimento da função menu_1_1. Os números
visualizados à esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 34 - Desenvolvimento da função menu_1_1. 76 void menu_1_1()
77 {
78 char opt[10];
79 int saida;
80 char errbuf[PCAP_ERRBUF_SIZE];
81 pcap_t *handle;
82 do {
83 cabecalho("MENU PRINCIPAL >>> 1-ESCUTA >>> 1-INTERFACE","");
84 printf("\t\t1 - Interface: ");
85
86 scanf("%s",opt);
87 memcpy(dev,opt,strlen(opt));
88 handle = pcap_open_live(dev,BUFSIZ,1,0,errbuf);
89 if (handle == NULL) {
90 printf("\n Opção inválida!");
91 __fpurge(stdin);
92 getchar();
93 saida = 0;
94 printf("\n");
95 } else {
96 __fpurge(stdin);
97 saida = 1;
98 }
99 } while (saida != 1);
100 }
Fonte: o autor, 2011.
103
3.4.7.5 Função menu_1_2
A função menu_1_2 é utilizada para impressão do menu de configuração do
endereço IP do dispositivo a ser monitorado na tela do operador e para efetuar a leitura do
endereço IP. A leitura do endereço IP é efetuada e gravada na variável ip_orig. Na Tabela 35
pode-se observar o desenvolvimento da função menu_1_2. Os números visualizados à
esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 35 - Desenvolvimento da função menu_1_2. 102 void menu_1_2()
103 {
104 char opt[30];
105
106 cabecalho("MENU PRINCIPAL >>> 1-ESCUTA >> 2-IP ORIGEM","");
107 printf("\t\t2 - IP Origem: ");
108
109 scanf("%s",opt);
110 memcpy(ip_orig,opt,strlen(opt));
111 __fpurge(stdin);
112 }
Fonte: o autor, 2011.
3.4.7.6 Função menu_1_3
A função menu_1_3 é utilizada para impressão do menu de configuração da porta de
origem ou destino UDP utilizada no filtro de captura na tela do operador, e para efetuar a
leitura do valor da porta. A leitura da porta de destino UDP é efetuada e gravada na variável
porta_dst. Na Tabela 36 observa-se o desenvolvimento da função menu_1_3. Os números
visualizados à esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 36 - Desenvolvimento da função menu_1_3. 114 void menu_1_3()
115 {
116 char opt[30];
117
118 cabecalho("MENU PRINCIPAL >>> 1-ESCUTA >>> 3-PORTA DESTINO","");
119 printf("\t\t3 - Porta Destino: ");
120
121 scanf("%s",opt);
122 memcpy(porta_dst,opt,strlen(opt));
123 __fpurge(stdin);
124 }
Fonte: o autor, 2011.
104
3.4.7.7 Função menu_2
A função menu_2 é utilizada para impressão do menu de configuração dos campos
do SIP. Ele recebe dois ponteiros do tipo char como argumento, o primeiro informa o campo
que está sendo alterado e o segundo informa o nome do campo seguido do valor original do
campo. O processo consiste em efetuar a leitura do novo valor do campo que está sendo
alterado através da leitura do teclado, depois efetuar a troca do valor da variável no arquivo
que armazena as informações dos campos do SIP através da função global troca_string. Caso
o usuário digite um valor inválido a função é repetida, e caso o arquivo de informações dos
campos SIP não exista ele é criado dentro desta função. Na Tabela 37 pode-se observar o
desenvolvimento da função menu_2. Os números visualizados à esquerda são apenas
identificadores das linhas, não fazendo parte do código.
Tabela 37 - Desenvolvimento da função menu_2. 126 void menu_2(char *campo, char *entire_str)
127 {
128 FILE *camp_data = NULL;
129 char opt[10];
130 char part_cab[200];
131 char part_func[200];
132 char new_value[50];
133 int saida;
134
135 memset(&part_cab,'\0',sizeof(char)*200);
136 memset(&part_func,'\0',sizeof(char)*200);
137 memset(&new_value,'\0',sizeof(char)*50);
138
139 sprintf(part_cab,"MENU PRINCIPAL >>> 2-DADOS ESCUTADOS >>> %s",campo);
140 sprintf(part_func,"%s=",campo);
141
142
143 do {
144 cabecalho(part_cab,"");
145 printf("\t\t1 - %s: ",campo);
146
147 scanf("%s",opt);
148
149 sprintf(new_value,"%s=%s",campo,opt);
150
151 if (opt != "") {
152 if (troca_string(arq_data_nome,entire_str,new_value) == 0) {
153 if ((camp_data = fopen(arq_data_nome,"r+"))) {
154 fseek(camp_data,0,SEEK_END);
155 fprintf(camp_data,"%s\n",new_value);
156 fclose(camp_data);
157 __fpurge(stdin);
158 saida = 1;
159 } else if ((camp_data = fopen(arq_data_nome,"w"))) {
160 fseek(camp_data,0,SEEK_END);
161 fprintf(camp_data,"%s\n",new_value);
162 fclose(camp_data);
163 __fpurge(stdin);
164 saida = 1;
165 } else {
166 printf("\n Problema gravando alteração,
verificar arquivo!");
167 __fpurge(stdin);
168 getchar();
169 saida = 1;
105
170 }
171 } else
172 saida = 1;
173 } else {
174 printf("\n Opção inválida!");
175 __fpurge(stdin);
176 getchar();
177 saida = 0;
178 printf("\n");
179 }
180 } while (saida != 1);
181 }
Fonte: o autor, 2011.
3.4.7.8 Função menu_3
A função menu_3 é utilizada na impressão da tela de injeção na tela do operador e
para efetuar a leitura de teclado que indica o início da injeção ou o cancelamento da injeção.
O tratamento da entrada de teclado não é efetuado nesta função. Na Tabela 38 pode-se
observar o desenvolvimento da função menu_3. Os números visualizados à esquerda são
apenas identificadores das linhas, não fazendo parte do código.
Tabela 38 - Desenvolvimento da função menu_3. 183 char menu_3()
184 {
185 char opt;
186
187 cabecalho("MENU PRINCIPAL >>> 3-INJEÇÃO",\
188 "Escolha (1-Iniciar) ou 'q' para cancelar a injeção a qualquer
momento.");
189 printf("\tEscolha: ");
190 __fpurge(stdin);
191 opt = getchar();
192 return(opt);
193 }
Fonte: o autor, 2011.
3.4.7.9 Função menu_4
A função menu_4 trata do controle da seção “Mostrar Resultados” e é utilizada para
impressão da tela juntamente com os pacotes capturados através na seção “Escuta” e os
pacotes capturados e injetados na seção “Injeção”. A Tabela 39 mostra o desenvolvimento da
função menu_4 onde pode-se observar a varredura dos arquivos de coleta e de resultado de
injeção nas linhas 217 a 223, e a cada arquivo é efetuada a impressão dos dados do arquivo
106
através do uso da função imprime_pkt. Os números visualizados à esquerda são apenas
identificadores das linhas, não fazendo parte do código.
Tabela 39 - Desenvolvimento da função menu_4. 195 void menu_4()
196 {
197 char opt;
198 int i;
199 char pathname[100];
200
201 do {
202 cabecalho("MENU PRINCIPAL >>> 4-MOSTRAR RESULTADOS",\
203 "Escolha 'q' para voltar.");
204 printf("\n\tANTES DA ALTERAÇÃO\n\n");
205 printf("\tPKT IP SRC\t\t\t\t\tIP DST\t\t\tSIP\n\n");
206 for (i=1;i<*arq_cap_cnt;i++) {
207 memset(pathname,'\0',sizeof(char)*100);
208 if (i < 10)
209 sprintf(pathname,"%s0%d.cap",arq_cap_nome,i);
210 else
211 sprintf(pathname,"%s%d.cap",arq_cap_nome,i);
212 imprime_pkt(pathname);
213 }
214 printf("\n\n\n\tDEPOIS DA ALTERAÇÃO\n\n");
215 printf("\tPKT IP SRC\t\t\t\t\tIP DST\t\t\tSIP\n\n");
216 for (i=1;i<*arq_res_cnt;i++) {
217 memset(pathname,'\0',sizeof(char)*100);
218 if (i < 10)
219 sprintf(pathname,"%s0%d.cap",arq_res_nome,i);
220 else
221 sprintf(pathname,"%s%d.cap",arq_res_nome,i);
222 imprime_pkt(pathname);
223 }
224 printf("\n\n\tEscolha: ");
225 __fpurge(stdin);
226 opt = getchar();
227 } while (opt != 'q');
228 __fpurge(stdin);
229 }
Fonte: o autor, 2011.
3.4.7.10 Função menu_5
A função menu_5 é responsável pelo controle da limpeza dos resultados. É utilizada
na impressão da tela da opção de limpeza de resultados na tela do operador e na exclusão dos
arquivos referentes a captura e injeção da seção “Injeção”. Essa tela informa que os resultados
estão sendo apagados, aguarda o tempo de 1s através do comando sleep18
e finaliza. Na
Tabela 40 pode-se observar o desenvolvimento da função menu_5. Os números visualizados à
esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 40 - Desenvolvimento da função menu_5. 231 void menu_5()
232 {
18
A função sleep efetua uma pausa do tempo em segundos passado como argumento para a fução
(CPLUSPLUS, 2011).
107
233 char comando[100];
234 char troca_valor[100];
235 cabecalho("MENU PRINCIPAL >>> 5-LIMPAR RESULTADOS",\
236 "Excluindo resultados...");
237 sprintf(comando,"rm -rf %s*.*",arq_res_nome);
238 system(comando);
239 sprintf(troca_valor,"ARQ_RES_TOTAL=%d",*arq_res_cnt);
240 troca_string(arq_info_nome,troca_valor,"ARQ_RES_TOTAL=0");
241 sleep(1);
242 }
Fonte: o autor, 2011.
3.4.7.11 Função menu_6
A função menu_6 é responsável pelo controle da limpeza geral dos arquivos do
software. É utilizada na impressão da tela da opção de limpeza geral na tela do operador e na
exclusão de todos os arquivos de armazenamento. O processo exclui os arquivos, informa a
exclusão dos dados, aguarda o tempo de 1s através do comando sleep, e finaliza. Na Tabela
41 pode-se observar o desenvolvimento da função menu_6. Os números visualizados à
esquerda são apenas identificadores das linhas, não fazendo parte do código.
Tabela 41 - Desenvolvimento da função menu_6. 244 void menu_6()
245 {
246 char comando[100];
247 cabecalho("MENU PRINCIPAL >>> 6-LIMPAR TUDO",\
248 "Excluindo tudo...");
249 sprintf(comando,"rm -rf %s*.*",arq_cap_local);
250 system(comando);
251 sleep(1);
252 }
Fonte: o autor, 2011.
3.4.8 Controle Principal
O controle principal é responsável por inicializar as variáveis globais, carregar os
valores de uma sessão de captura já salvos, carregar valores dos campos SIP já salvos e
controlar o acesso às demais seções do software. O código do controle principal faz parte do
arquivo main.c e a função é denominada main.
A inicialização das variáveis é feita no início da execução do software. Como as
variáveis globais são praticamente ponteiros, cabe ao controle principal fazer a alocação de
108
memória para cada ponteiro descrito na seção 3.4.4. A inicialização é feita através da função
malloc19
. Na Tabela 42 pode-se verificar o início do código do controle principal e nas linhas
13 a 32 a inicialização das variáveis globais. Os números visualizados à esquerda são apenas
identificadores das linhas não fazendo parte do código.
Tabela 42 - Inicialização das variáveis globais. 1 #include "config.h"
2 #include "escuta.h"
3 #include "menu.h"
4 #include "altera.h"
5 #include "injection.h"
6
7 int main()
8 {
9 char com_cria[50];
10 FILE *file_info;
11 char opt;
12
13 dev=(char *)malloc(5*sizeof(char));
14 ip_orig=(char *)malloc(20*sizeof(char));
15 porta_dst=(char *)malloc(6*sizeof(char));
16 arq_info_nome=(char *)malloc(100*sizeof(char));
17 arq_cap_nome=(char *)malloc(100*sizeof(char));
18 arq_res_nome=(char *)malloc(100*sizeof(char));
19 arq_data_nome=(char *)malloc(100*sizeof(char));
20 arq_cap_cnt=(int *)malloc(3*sizeof(int));
21 arq_res_cnt=(int *)malloc(3*sizeof(int));
22 arq_cap_local=(char *)malloc(50*sizeof(char));
23 int_arq=(char *)malloc(10*sizeof(char));
24 stop_thread=(int *)malloc(5*sizeof(int));
25 sip_caller=(char *)malloc(50*sizeof(char));
26 sip_callern=(char *)malloc(50*sizeof(char));
27 sip_called=(char *)malloc(50*sizeof(char));
28 sip_calledn=(char *)malloc(50*sizeof(char));
29 sip_username=(char *)malloc(50*sizeof(char));
30 sip_usernamen=(char *)malloc(50*sizeof(char));
31 sip_password=(char *)malloc(50*sizeof(char));
32 sip_passwordn=(char *)malloc(50*sizeof(char));
Fonte: o autor, 2011.
A próxima etapa executada pelo controle principal após a inicialização das variáveis,
é o carregamento dos valores salvos e as definições básicas para a operação do sofware. Na
Tabela 43 pode-se verificar a continuação do controle principal, os números visualizados à
esquerda são apenas identificadores das linhas do arquivo, não fazendo parte do código. Nas
linhas 34 a 38 são definidos o local onde serão gravados os arquivos e os nomes dos arquivos.
Nota-se que os nomes dos arquivos de captura da seção “Escuta” e da seção “Injeção” estão
incompletos, eles são completados no momento do armazenamento de acordo com a
sequência de captura. Na linha 40 o controle verifica a existência do arquivo de informações
da sessão de captura salva, nas linhas seguintes faz a leitura dos dados utilizando a função
global valor_string. Na linha 59 ocorre a mesma situação com o arquivo de informações do
protocolo SIP, verifica-se a existência do arquivo e faz-se a leitura dos dados.
19
Malloc é uma função da biblioteca stdlib.h que aloca um espaço de memória para uma determinada variável
sem alterar os dados já contidos na memória (CPLUSPLUS, 2011).
109
Tabela 43 - Carregamento dos valores salvos. 34 sprintf(arq_cap_local,"./capture/");
35 sprintf(arq_info_nome,"%sinfo_sessao.txt",arq_cap_local);
36 sprintf(arq_cap_nome,"%scapture_",arq_cap_local);
37 sprintf(arq_res_nome,"%scapture_res_",arq_cap_local);
38 sprintf(arq_data_nome,"%scapture_data.txt",arq_cap_local);
39
40 if ((file_info = fopen(arq_info_nome,"r"))) {
41 valor_string(file_info,"DEV=",dev,'\n','\0');
42 valor_string(file_info,"IP_ORIG=",ip_orig,'\n','\0');
43 valor_string(file_info,"PORTA_DST=",porta_dst,'\n','\0');
44 valor_string(file_info,"ARQ_CAP_TOTAL=",int_arq,'\n','\0');
45 *arq_cap_cnt = atoi(int_arq);
46 if (valor_string(file_info,"ARQ_RES_TOTAL=",int_arq,'\n','\0') > 0)
47 *arq_res_cnt = atoi(int_arq);
48 else
49 *arq_res_cnt = 0;
50 fclose(file_info);
51 } else {
52 sprintf(dev,"eth1");
53 sprintf(ip_orig,"192.168.33.2");
54 sprintf(porta_dst,"5060");
55 *arq_res_cnt = 0;
56 *arq_cap_cnt = 0;
57 }
58
59 if ((file_info = fopen(arq_data_nome,"r"))) {
60 valor_string(file_info,"CALLER_ORIG=",sip_caller,'\n','\0');
61 valor_string(file_info,"CALLER=",sip_callern,'\n','\0');
62 valor_string(file_info,"CALLED_ORIG=",sip_called,'\n','\0');
63 valor_string(file_info,"CALLED=",sip_calledn,'\n','\0');
64 valor_string(file_info,"USERNAME_ORIG=",sip_username,'\n','\0');
65 valor_string(file_info,"USERNAME=",sip_usernamen,'\n','\0');
66 valor_string(file_info,"PASSWORD=",sip_passwordn,'\n','\0');
67 fclose(file_info);
68 };
Fonte: o autor, 2011.
Outra etapa executada pelo controle principal é a verificação da existência do
diretório de armazenamento dos dados. Pode-se verificar na Tabela 44 a verificação do
diretório e a criação do mesmo no caso de sua inexistência. Os números à esquerda são apenas
identificadores das linhas do arquivo não fazendo parte do código.
Tabela 44 - Verificação do diretório de armazenamento. 71 if (fopen(arq_cap_local,"r") == NULL) {
72 memset(&com_cria,0,sizeof(char)*50);
73 sprintf(com_cria,"mkdir %s",arq_cap_local);
74 system(com_cria);
75 }
Fonte: o autor, 2011.
A última etapa a ser executada pelo controle principal é o controle do acesso às
demais seções. Na Tabela 45 observa-se o desenvolvimento do controle de acesso. Os
números à esquerda são identificadores das linhas do arquivo não fazendo parte do código.
Tabela 45 - Desenvolvimento do controle de acesso principal. 77 do {
78 opt = menu_main();
79 switch(opt) {
80 case '1':
81 if (escuta_func() == 1) {
82 printf(" ");
83 }
84 break;
85 case '2':
86 if (*arq_cap_cnt > 0)
87 dados_esc_menu();
110
88 else {
89 cabecalho("MENU PRINCIPAL >>> 2-DADOS
ESCUTADOS","Não existem dados a serem visualizados!\n");
90 sleep(1);
91 }
92 break;
93 case '3':
94 if (*arq_cap_cnt > 0)
95 if (*arq_res_cnt > 0) {
96 cabecalho("MENU PRINCIPAL >>> 3-
INJEÇÃO","Você deve limpar os resultados primeiro!\n");
97 sleep(2);
98 } else
99 injecao();
100 else {
101 cabecalho("MENU PRINCIPAL >>> 3-INJEÇÃO","Não
existem dados a serem injetados!\n");
102 sleep(1);
103 }
104 break;
105 case '4':
106 if (*arq_res_cnt == 0) {
107 cabecalho("MENU PRINCIPAL >>> 4-MOSTRAR
RESULTADOS","Você não possui resultados para mostrar!\n");
108 sleep(2);
109 } else
110 menu_4();
111 break;
112 case '5':
113 menu_5();
114 *arq_res_cnt = 0;
115 break;
116 case '6':
117 menu_6();
118 *arq_cap_cnt = 0;
119 break;
120 case 'q':
121 printf("\n\t\tSaindo...\n\n\n\n");
122 }
123 } while (opt != 'q');
124
125 sleep(1);
126 return(0);
127 }
Fonte: o autor, 2011.
O controle de acesso é feito através do uso de um laço do while20
onde a função
menu_main, responsável pela impressão da tela principal na tela do operador e pela leitura da
opção do operador através do teclado, é executada e seu retorno analisado para determinar a
qual seção disponível o acesso será efetuado.
Observando a Tabela 45, pode-se verificar sete diferentes opções de acesso
disponíveis. A opção “1” define o acesso a função escuta_func desenvolvida no arquivo
escuta.c que trata da seção “Escuta”. A opção “2” define o acesso a função dados_esc_menu
desenvolvida no arquivo altera.c que trata da seção “Dados Escutados”. A opção “3” define o
acesso a função injecao desenvolvida no arquivo injection.c que trata da seção “Injeção”. A
opção “4” define o acesso a função menu_4 desenvolvida no arquivo menu.c que trata da
seção “Mostrar Resultados”. A opção “5” define o acesso a função menu_5 desenvolvida no
20
Do while pode ser definido como um comando onde o do determina um trecho de código a ser executado
enquanto a condição determinada pelo while seja verdadeira (CPLUSPLUS, 2011).
111
arquivo menu.c que trata da seção “Limpar Resultados”. A opção “6” define o acesso a função
menu_6 desenvolvida no arquivo menu.c que trata da seção “Limpar Tudo”. A sétima opção é
a de finalização do software através da letra „q‟.
3.4.9 Controle de Escuta
O controle de escuta está armazenado no arquivo escuta.c, ele é responsável pela
criação do filtro de captura através da leitura dos dados que compõe o filtro e pela seleção da
interface através da qual a captura dos pacotes será executada. Esse controle é também
responsável pelo controle da captura dos dados.
A primeira função executada dentro do controle de escuta é a função escuta_func.
Essa função executa uma outra função já mencionada denominada menu_1 que é responsável
pela impressão da tela de escuta na tela do operador e pela leitura da opção do operador. A
opção após lida é retornada a função escuta_func que seleciona qual das opções será acessada.
Na Tabela 46 pode-se verificar o desenvolvimento da função escuta_func, os números
visualizados à esquerda são apenas identificadores das linhas do arquivo não fazendo parte do
código.
Tabela 46 - Desenvolvimento do controle de acesso da seção "Escuta". 84 int escuta_func()
85 {
86 char opt;
87
88 do {
89 opt = menu_1();
90 switch(opt) {
91 case '1':
92 memset(dev,'\0',5);
93 menu_1_1();
94 break;
95 case '2':
96 memset(ip_orig,'\0',20);
97 menu_1_2();
98 break;
99 case '3':
100 memset(porta_dst,'\0',6);
101 menu_1_3();
102 break;
103 case '4':
104 captura();
105 break;
106 }
107 } while (opt != 'q');
108 return(0);
109 }
Fonte: o autor, 2011.
112
No caso do operador selecionar as opções “1”, “2” ou “3”, ele estará acessando a
configuração da interface, do endereço IP do dispositivo monitorado e da porta UDP dos
pacotes. Se o operador escolher a opção “4”, ele estará acessando a área de captura que é
desenvolvida na Tabela 47 através da função captura. Os números visualizados à esquerda
são apenas identificadores das linhas do arquivo e não fazem parte do código.
Tabela 47 - Desenvolvimento da função de captura da seção "Escuta". 31 int captura()
32 {
33 struct bpf_program fp;
34 char filter_exp[100];
35 FILE *file_info;
36
37 char comando[50];
38 bpf_u_int32 mask;
39 bpf_u_int32 net;
40
41 *arq_cap_cnt = 1;
42 sprintf(comando,"rm -rf %s*",arq_cap_local);
43 system(comando);
44
45 file_info = fopen(arq_info_nome,"w");
46 fprintf(file_info,"DEV=%s\n",dev);
47 fprintf(file_info,"IP_ORIG=%s\n",ip_orig);
48 fprintf(file_info,"PORTA_DST=%s\n",porta_dst);
49
50 sprintf(filter_exp,"host %s and (udp src port %s or udp dst port %s)"\
51 ,ip_orig,porta_dst,porta_dst);
52 // carrega net e mask
53 pcap_lookupnet(dev, &net, &mask, errbuf);
54 // captura
55 if ((handle = pcap_open_live(dev,BUFSIZ,1,0,errbuf))) {
56 pcap_setnonblock(handle,0,errbuf);
57 pcap_compile(handle, &fp, filter_exp, 0, net);
58 pcap_setfilter(handle, &fp);
59
60 cabecalho("MENU PRINCIPAL >>> 1-ESCUTA >>> 4-CAPTURA",\
61 "Pressione 'q' para encerrar a captura...");
62 printf("\tPKT IP SRC\t\t\t\t\tIP DST\t\t\tSIP\n\n");
63
64 arq_pcap_nome = arq_cap_nome;
65 arq_pcap_cnt = arq_cap_cnt;
66
67 pthread_create (&pollThread, 0, PollKbd,0);
68 pthread_create (&crunchThread, 0, Cruncher,0);
69
70 pthread_join (pollThread, 0);
71 pthread_join (crunchThread, 0);
72
73 sprintf(int_arq,"%d",*arq_cap_cnt);
74 fprintf(file_info,"ARQ_CAP_TOTAL=%s\n",int_arq);
75 fclose(file_info);
76
77 pcap_close(handle);
78
79 return 0;
80 }
81 return 1;
82 }
Fonte: o autor, 2011.
Observando a função captura, pode-se verificar inicialmente a definição de algumas
variáveis utilizadas na função e a exclusão de todos os arquivos que podem estar
armazenados. Essa operação visa garantir que a partir do momento que o operador inicia o
processo de captura, nenhum dado antigo permanece armazenado. Depois da exclusão dos
113
dados é criada a expressão do filtro de captura na linha 50. Na linha 53 é efetuada a leitura
dos dados de endereçamento da interface que está sendo utilizada para a captura. Esses dados
são necessários quando o filtro é aplicado na interface.
Iniciando o processo de captura é efetuada a abertura da interface na linha 55, em
caso de sucesso é continuado o processo setando o desbloqueio do processo de captura da
libpcap na linha 56, compilando o filtro na linha 57 e aplicando o filtro de captura na linha 58.
Nas linhas 60 a 62 é preparada a tela de captura com o uso da função cabecalho e setado na
linha 64 para que o ponteiro utilizado pela captura para denominar os arquivos, aponte para o
ponteiro que armazena o arquivo de captura da seção “Escuta”. É também setado na linha 65
para que o ponteiro utilizado pela captura para contar a sequência de pacotes capturados,
aponte para o ponteiro que armazena a contagem de arquivos capturados na seção “Escuta”.
Com todas as variáveis setadas chega o momento de iniciar a captura. Como
observado nas linhas 67 e 68, são criadas duas threads para iniciar a captura. Depois as
mesmas threads são combinadas para que o código só continue a ser executado quando ambas
terminarem sua execução. Depois disso a variável de contagem de pacotes capturados é
armazenada no arquivo de informações da sessão na linha 74.
As threads executadas na função captura podem ser visualizadas na Tabela 48. Os
números visualizados à esquerda são apenas identificadores das linhas do arquivo e não fazem
parte do código.
Tabela 48 - Desenvolvimento das threads de controle da seção "Escuta". 5 pcap_t *handle;
6 char errbuf[PCAP_ERRBUF_SIZE];
7
8 pthread_t crunchThread, pollThread;
9
10 void* Cruncher (void* info)
11 {
12 do {
13 pcap_dispatch(handle,-1,callback,NULL);
14 } while (1);
15 return (void*) 0;
16 }
17
18 void* PollKbd (void* info)
19 {
20 char ch;
21 do {
22 rl_ttyset(0);
23 ch = getchar();
24 rl_ttyset(1);
25 } while (ch != 'q');
26 pthread_cancel(crunchThread);
27
28 return (void*) 0;
29 }
Fonte: o autor, 2011.
114
Como mencionado, duas threads são executadas para que o processo de captura seja
executado. Uma das threads denominada Cruncher ativa a captura. A thread PollKdb faz a
leitura do teclado, utiliza a função já conhecida rl_ttyset para setar o terminal para efetuar a
leitura do teclado sem a confirmação com a tecla Enter. Depois disso a configuração do
terminal é restaurada. Isso permite ao operador cancelar a captura a qualquer momento apenas
pressionando a tecla „q‟, quebrando o laço do while e cancelando a thread de captura através
do comando pthread_cancel. Essencialmente, uma thread controla a execução da outra.
3.4.10 Controle de Alteração
O controle de alteração está armazenado no arquivo altera.c, ele é responsável pela
verificação dos campos do SIP nos pacotes capturados mostrando os valores originais para o
operador e fornecendo o controle da alteração desses campos.
O primeiro processo dentro da função de controle dados_esc_menu, é a criação do
laço do while que executa a função dados_esc responsável pela impressão da tela da seção
“Dados Escutados” e pela leitura de teclado que direciona o operador a um dos campos SIP a
serem alterados. Dentro do laço do while, conforme a opção retornada pela função dados_esc,
é executada a função menu_2 com diferentes argumentos. Na Tabela 49 pode ser observado o
desenvolvimento do controle de menu da seção “Dados Escutados”. Os números visualizados
à esquerda são apenas identificadores das linhas do arquivo e não fazem parte do código.
Tabela 49 - Controle de menu da seção "Dados Escutados". 84 void dados_esc_menu()
85 {
86 char opt;
87 char *entire_value;
88
89 do {
90 opt = dados_esc();
91 switch(opt) {
92 case '1':
93 entire_value = (char *)malloc(sizeof(char)*50);
94 sprintf(entire_value,"CALLER=%s",sip_callern);
95 menu_2("CALLER",entire_value);
96 break;
97 case '2':
98 entire_value = (char *)malloc(sizeof(char)*50);
99 sprintf(entire_value,"CALLED=%s",sip_calledn);
100 menu_2("CALLED",entire_value);
101 break;
102 case '3':
103 entire_value = (char *)malloc(sizeof(char)*50);
104 sprintf(entire_value,"USERNAME=%s",sip_usernamen);
105 menu_2("USERNAME",entire_value);
106 break;
115
107 case '4':
108 entire_value = (char *)malloc(sizeof(char)*50);
109 sprintf(entire_value,"PASSWORD=%s",sip_passwordn);
110 menu_2("PASSWORD",entire_value);
111 break;
112 }
113 } while (opt != 'q');
114 __fpurge(stdin);
115 }
Fonte: o autor, 2011.
Na Tabela 50 pode-se observar o início da função dados_esc. Os números
observados à esquerda são apenas identificadores das linhas e não fazem parte do código.
Tabela 50 - Parte inicial da função dados_esc. 5 char dados_esc()
6 {
7 FILE *arq_data = NULL;
8 FILE *camp_data = NULL;
9 int i;
10 char *pathname;
11 char opt;
12
13 char var_aux[10];
14
15 memset(&var_aux,'\0',sizeof(char)*10);
16
17 cabecalho("MENU PRINCIPAL >>> 2-DADOS ESCUTADOS","");
18 printf("\tPKT IP SRC\t\t\t\t\tIP DST\t\t\tSIP\n\n");
19
20 pathname=(char*)malloc(50*sizeof(char));
21 for (i=1;i < *arq_cap_cnt;i++) {
22 if (*arq_cap_cnt < 10)
23 sprintf(pathname,"%s0%d.cap",arq_cap_nome,i);
24 else
25 sprintf(pathname,"%s%d.cap",arq_cap_nome,i);
26 arq_data = fopen(pathname,"r");
27 if (i==1) {
28 valor_sip_string(arq_data,"From:","sip:",sip_caller,'@','\0');
29 valor_sip_string(arq_data,"To:","sip:",sip_called,'@','\0');
30 }
31 if (valor_string(arq_data,"Authorization",var_aux,' ','"') == 1)
32 valor_string(arq_data,"username=",sip_username,',','"');
33 fclose(arq_data);
34 imprime_pkt(pathname);
35 };
Fonte: o autor, 2011.
Inicialmente a função dados_esc varre os arquivos capturados buscando os campos
caller, called e username. Depois de encontrados os valores dos campos, é utilizada a função
imprime_pkt para imprimir na tela os pacotes capturados na seção “Escuta”.
Na Tabela 51 é iniciado o processo de gravação dos dados dos campos no arquivo de
armazenamento dos campos SIP. Pode-se observar também a gravação de uma informação na
variável password que visa informar o operador que a senha não pode ser detectada e está no
formato MD5. Os números visualizados à esquerda são apenas identificadores das linhas do
arquivo não fazendo parte do código.
Tabela 51 - Gravação dos campos SIP no arquivo. 37 sprintf(sip_password,"MD5");
38
39 camp_data = fopen(arq_data_nome,"r+");
40 if (camp_data == NULL)
41 camp_data = fopen(arq_data_nome,"w");
116
42 if (valor_string(camp_data,"CALLER_ORIG=",sip_caller,'\n','\0') == 0) {
43 fseek(camp_data,0,SEEK_END);
44 fprintf(camp_data,"CALLER_ORIG=%s\n",sip_caller);
45 }
46 if (valor_string(camp_data,"CALLED_ORIG=",sip_called,'\n','\0') == 0) {
47 fseek(camp_data,0,SEEK_END);
48 fprintf(camp_data,"CALLED_ORIG=%s\n",sip_called);
49 }
50 if (valor_string(camp_data,"USERNAME_ORIG=",sip_username,'\n','\0') == 0) {
51 fseek(camp_data,0,SEEK_END);
52 fprintf(camp_data,"USERNAME_ORIG=%s\n",sip_username);
53 }
54 if (valor_string(camp_data,"CALLER=",sip_callern,'\n','\0') == 0) {
55 fseek(camp_data,0,SEEK_END);
56 fprintf(camp_data,"CALLER=%s\n",sip_caller);
57 memcpy(sip_callern,sip_caller,sizeof(char)*50);
58 }
59 if (valor_string(camp_data,"CALLED=",sip_calledn,'\n','\0') == 0) {
60 fseek(camp_data,0,SEEK_END);
61 fprintf(camp_data,"CALLED=%s\n",sip_called);
62 memcpy(sip_calledn,sip_called,sizeof(char)*50);
63 }
64 if (valor_string(camp_data,"USERNAME=",sip_usernamen,'\n','\0') == 0) {
65 fseek(camp_data,0,SEEK_END);
66 fprintf(camp_data,"USERNAME=%s\n",sip_username);
67 memcpy(sip_usernamen,sip_username,sizeof(char)*50);
68 }
69 valor_string(camp_data,"PASSWORD=",sip_passwordn,'\n','\0');
70
71 fclose(camp_data);
Fonte: o autor, 2011.
Na Tabela 52 é impresso o menu de seleção do campo SIP a ser alterado e aguardada
a entrada de teclado pelo operador informando qual campo será acessado para efetuar a
alteração. O retorno da função dados_esc é processado pela função dados_esc_menu
observada na Tabela 49. Os números observados à esquerda estão apenas identificando as
linhas do arquivo não fazendo parte do código.
Tabela 52 - Impressão do menu de acesso aos campos SIP. 73 printf("\n\n\t CAMPO\t\tESCUTA\t\tINJEÇÃO\n\n");
74 printf("\t1 - Caller\t\t%s \t%s\n",sip_caller,sip_callern);
75 printf("\t2 - Called\t\t%s \t%s\n",sip_called,sip_calledn);
76 printf("\t3 - Username\t\t%s \t%s\n",sip_username,sip_usernamen);
77 printf("\t4 - Password\t\t%s \t%s\n",sip_password,sip_passwordn);
78 printf("\n\n\tEscolha o campo que deseja alterar ou 'q' para voltar: ");
79 __fpurge(stdin);
80 opt = getchar();
81 return(opt);
82 }
Fonte: o autor, 2011.
3.4.11 Controle de Injeção
Superficialmente, o controle de injeção é responsável por injetar os pacotes com as
alterações efetuadas pelo operador, fazer a captura dos pacotes resposta dos pacotes injetados,
e fazer a sincronia desse diálogo entre o analisador e o servidor SIP.
117
O processo inicia sob o comando do operador. O operador pode decidir por iniciar o
processo de injeção ou voltar para o menu principal. A Tabela 53 mostra o desenvolvimento
da função que controla a interface com o operador. Os números observados à esquerda são
apenas identificadores das linhas do arquivo, não fazendo parte do código.
Tabela 53 - Controle interface operador seção "Injeção". 446 int injecao()
447 {
448 char opt;
449
450 do {
451 opt = menu_3();
452 switch(opt) {
453 case '1':
454 pthread_create (&injThread, 0, inj,0);
455 pthread_create (&caninjThread, 0, caninj,0);
456 pthread_join (injThread, 0);
457 pthread_join (caninjThread, 0);
458 opt = 'q';
459 break;
460 }
461 } while (opt != 'q');
462 __fpurge(stdin);
463 return(0);
464 }
Fonte: o autor, 2011.
Se o operador optar por iniciar o processo de injeção, duas threads são criadas.
Semelhantes ao processo de captura da seção “Escuta”, essas threads são necessárias para que
o operador consiga parar o processo de injeção utilizando uma entrada de teclado. Enquanto
uma thread é responsável pelo controle da injeção e captura dos pacotes, a outra thread é
responsável pela leitura de teclado que define se o processo deve ou não continuar. A Tabela
54 mostra o desenvolvimento dessas duas threads.
Tabela 54 - Desenvolvimento das threads de controle de injeção e captura. 426 void* inj (void* info)
427 {
428 injeta();
429 return (void*) 0;
430 }
431
432 void* caninj (void* info)
433 {
434 char ch;
435
436 do {
437 rl_ttyset(0);
438 ch = getchar();
439 rl_ttyset(1);
440 } while (ch != 'q');
441 *stop_thread = 1;
442 pthread_cancel(injThread);
443 return (void*) 0;
444 }
Fonte: o autor, 2011.
A thread inj inicia o processo de injeção e captura executando a função injeta.
Resumidamente, a função injeta é formada por um laço do while que só finaliza
quando a flag fim é setada, sendo esta setada pelo próprio processo. Dentro deste laço, o
118
processo inicia verificando os pacotes salvos pela seção “Escuta”. O arquivo em questão é
duplicado e salvo com o padrão de nomenclatura dos arquivos da seção “Injeção”. Essa
duplicação visa manter o arquivo de captura original salvo para a posterior comparação dos
dados capturados na seção “Escuta” com os injetados e capturados na seção “Injeção”.
Cada arquivo de pacote é aberto e o endereço IP de origem verificado. É através da
comparação do endereço de origem salvo no arquivo com o endereço armazenado na variável
ip_orig que o processo sabe se o pacote em questão deve ser injetado ou capturado. De acordo
com essa comparação ou é iniciado o processo de captura ou o processo de injeção.
Dentro do processo de injeção, são feitas as alterações no arquivo de captura de
acordo com as alterações efetuadas pelo operador nos campos SIP. Depois disso o pacote é
criado e injetado. Dentro do processo de captura é efetuada a captura dos pacotes na interface
de acordo com um filtro criado. Dessa forma o processo é repetido até que os pacotes
capturados na seção “Escuta” se esgotem ou até que a resposta do servidor SIP a uma
requisição enviada através da seção “Injeção” seja diferente da capturada na seção “Escuta”.
A Tabela 55 mostra o início do desenvolvimento da função injeta. Nesta parte do
desenvolvimento são declaradas todas as variáveis utilizadas pela função.
Tabela 55 - Declaração das variáveis na função injeta. 84 int injeta()
85 {
86 struct sniff_ethernet *ether_inj;
87 struct sniff_ip *ip_inj;
88 struct sniff_udp *udp_inj;
89 struct pseudo_header *pseudo_inj;
90 char *payload_inj;
91
92 u_char *packet;
93 int packet_size;
94
95 int sentbytes,i,j,l,m,sai;
96 char mac_add[3],mac_src[20],mac_dst[20],ch;
97
98 u_short *pack_ip,*pseudo;
99 char udp_len;
100 char pseudo_zero;
101 char pad_byte;
102
103 char *ip_vhl,*ip_tos,*ip_id,*ip_ttl,*ip_off,*ip_p,*ip_src,*ip_dst;
104 char *udp_src,*udp_dst;
105
106 char comando[100];
107 char var_aux[10];
108 fpos_t posit;
109
110 char sip_tag_1[30];
111 char sip_tag_2[30];
112 char sip_tag_aux[30];
113 char sip_caller_1[30];
114 char sip_caller_2[30];
115 char sip_called_1[30];
116 char sip_called_2[30];
117 char sip_username_1[30];
118 char sip_username_2[30];
119
119
120 /* MD5 ... */
121 md5_state_t state;
122 md5_byte_t digest[16];
123 char hex_output[16*2 + 1];
124 char md5_atual[16*2 + 1];
125 char nonce_atual[16*2 + 1];
126 int di;
127
128 char sip_user[100];
129 char sip_realm[100];
130 //char sip_passwd[100];
131 char sip_nonce[100];
132 char sip_uri[100];
133
134 char A1[200];
135 char A2[200];
136 char A3[200];
137 char md5_1[16*2 + 1];
138 char md5_2[16*2 + 1];
139
140 char *acha_var, *troca_por;
Fonte: o autor, 2011.
Depois de declaradas as variáveis, a função inicia a alocação de memória para os
ponteiros, posiciona o início da injeção no pacote 01 como pode ser observado na linha 158
da Tabela 56. Os números observados à esquerda são apenas identificadores das linhas do
arquivo não fazendo parte do código.
Tabela 56 - Alocação de memória das variáveis. 142 printf("\n\n\tPKT IP SRC\t\t\t\t\tIP DST\t\t\tSIP\n\n");
143
144 pathcap=(char *)malloc(sizeof(char)*50);
145 pathcap_aux=(char *)malloc(sizeof(char)*50);
146
147 ip_vhl=(char *)malloc(sizeof(char)*2);
148 ip_tos=(char *)malloc(sizeof(char)*2);
149 ip_id=(char *)malloc(sizeof(char)*4);
150 ip_off=(char *)malloc(sizeof(char)*4);
151 ip_ttl=(char *)malloc(sizeof(char)*2);
152 ip_p=(char *)malloc(sizeof(char)*2);
153 ip_src=(char *)malloc(sizeof(char)*22);
154 ip_dst=(char *)malloc(sizeof(char)*22);
155 udp_src=(char *)malloc(sizeof(char)*4);
156 udp_dst=(char *)malloc(sizeof(char)*4);
157
158 *arq_res_cnt = 1;
159 fim = 0;
Fonte: o autor, 2011.
A Tabela 57 mostra o início do processo de injeção e captura onde é realizada a
comparação entre o endereço IP de origem armazenado no arquivo com o endereço IP do
dispositivo armazenado na variável ip_orig (linha 170). Através desta comparação é possível
saber se o pacote originou do dispositivo monitorado ou do servidor SIP. Pode-se observar
também a duplicação do arquivo do pacote armazenado (linhas 171 a 181) para que as
alterações não sejam efetuadas no arquivo original. Depois da duplicação do arquivo é
iniciado o processo de alteração do arquivo duplicado (linhas 182 a 193) de acordo com as
alterações sugeridas pelo operador. Os números visualizados à esquerda são apenas
identificadores das linhas do arquivo, não fazendo parte do código.
120
Tabela 57 - Início do processo de injeção e captura. 161 do {
162 if (*arq_res_cnt < 10)
163 sprintf(pathcap,"%s0%d.cap",arq_cap_nome,*arq_res_cnt);
164 else
165 sprintf(pathcap,"%s%d.cap",arq_cap_nome,*arq_res_cnt);
166 if ((cap_file = fopen(pathcap,"r"))) {
167 memset(ip_src,'\0',sizeof(char)*20);
168 valor_string(cap_file,"IP_SRC=",ip_src,'\n','\0');
169 fclose(cap_file);
170 if (strcmp(ip_src,ip_orig) == 0) {
171 memset((char *)comando,'\0',sizeof(char)*100);
172 if (*arq_res_cnt < 10) {
173 sprintf(comando,"cp -f %s
%s0%d.cap",pathcap,arq_res_nome,*arq_res_cnt);
174 memset(pathcap,'\0',sizeof(char)*50);
175
sprintf(pathcap,"%s0%d.cap",arq_res_nome,*arq_res_cnt);
176 } else {
177 sprintf(comando,"cp -f %s
%s%d.cap",pathcap,arq_res_nome,*arq_res_cnt);
178 memset(pathcap,'\0',sizeof(char)*50);
179
sprintf(pathcap,"%s%d.cap",arq_res_nome,*arq_res_cnt);
180 }
181 system(comando);
182 sprintf(sip_caller_1,"sip:%s@",sip_caller);
183 sprintf(sip_caller_2,"sip:%s@",sip_callern);
184 sprintf(sip_called_1,"sip:%s@",sip_called);
185 sprintf(sip_called_2,"sip:%s@",sip_calledn);
186 sprintf(sip_username_1,"username=\"%s\"",sip_username);
187 sprintf(sip_username_2,"username=\"%s\"",sip_usernamen);
188 if (strcmp(sip_caller_1,sip_caller_2) != 0)
189 troca_string(pathcap,sip_caller_1,sip_caller_2);
190 if (strcmp(sip_called_1,sip_called_2) != 0)
191 troca_string(pathcap,sip_called_1,sip_called_2);
192 if (strcmp(sip_username_1,sip_username_2) != 0)
193
troca_string(pathcap,sip_username_1,sip_username_2);
Fonte: o autor, 2011.
Na Tabela 58 inicia-se o processo de autenticação do SIP. Depois de efetuadas as
alterações no pacote duplicado, faz-se uma verificação no pacote a ser injetado para saber se
existem dados referentes a autenticação. Se os dados da autenticação existirem no pacote que
está sendo injetado, são verificados os pacotes anteriores para extrair os dados da requisição
de autenticação. A requisição de autenticação é caracterizada pelo campo WWW-Authenticate
no pacote recebido do servidor. Nas linhas 226 a 234 é efetuada a leitura dos dados enviados
pelo servidor para compor a hash21
MD5 utilizada na autenticação SIP. Como já mencionado,
são utilizados os dados realm, nonce, username e uri na composição da chave de autenticação
do SIP. Depois do processo de leitura dos dados, é efetuada a geração da chave com o auxílio
das funções do arquivo md5.c. Depois de gerada a chave, os dados são incluídos no pacote
que está sendo injetado com o uso da função troca_string como pode ser observado nas linhas
270 a 277. Os números visualizados à esquerda são apenas identificadores das linhas do
arquivo não fazendo parte do código.
21
Uma hash pode ser definida como uma sequência de bits gerada por um algoritmo (WALL, WATSON e
WHITIS, 1999).
121
Tabela 58 - Autenticação do SIP. 216 cap_file = fopen(pathcap,"r");
217 if (valor_string(cap_file,"Authorization",var_aux,' ','\0') == 1) {
218 h = *arq_res_cnt - 2;
219 memset(pathcap_aux,'\0',sizeof(char)*50);
220 if (h < 10)
221 sprintf(pathcap_aux,"%s0%d.cap",arq_res_nome,h);
222 else
223 sprintf(pathcap_aux,"%s%d.cap",arq_res_nome,h);
224 if ((cap_file_ant = fopen(pathcap_aux,"r"))) {
225 if (valor_string(cap_file_ant,"WWW-
Authenticate",var_aux,' ','"') == 1) {
226
valor_string(cap_file_ant,"realm=",sip_realm,',','"');
227
valor_string(cap_file_ant,"nonce=",sip_nonce,'\r','"');
228 }
229 fclose(cap_file_ant);
230 }
231 valor_string(cap_file,"username=",sip_user,',','"');
232 valor_string(cap_file,"uri=",sip_uri,',','"');
233 valor_string(cap_file,"response=",md5_atual,',','"');
234 valor_string(cap_file,"nonce=",nonce_atual,',','"');
235
236 strcat(A1,sip_user);
237 strcat(A1,":");
238 strcat(A1,sip_realm);
239 strcat(A1,":");
240 strcat(A1,sip_passwordn);
241
242 strcat(A2,"INVITE");
243 strcat(A2,":");
244 strcat(A2,sip_uri);
245
246 md5_init(&state);
247 md5_append(&state, (const md5_byte_t *)A1, strlen(A1));
248 md5_finish(&state, digest);
249 for (di = 0; di < 16; ++di)
250 sprintf(md5_1 + di * 2, "%02x", digest[di]);
251 md5_init(&state);
252 md5_append(&state, (const md5_byte_t *)A2, strlen(A2));
253 md5_finish(&state, digest);
254 for (di = 0; di < 16; ++di)
255 sprintf(md5_2 + di * 2, "%02x", digest[di]);
256
257 strcat(A3,md5_1);
258 strcat(A3,":");
259 strcat(A3,sip_nonce);
260 strcat(A3,":");
261 strcat(A3,md5_2);
262
263 md5_init(&state);
264 md5_append(&state, (const md5_byte_t *)A3, strlen(A3));
265 md5_finish(&state, digest);
266 for (di = 0; di < 16; ++di)
267 sprintf(hex_output + di * 2, "%02x", digest[di]);
268 fclose(cap_file);
269
270 acha_var = (char *)malloc(sizeof(char)*100);
271 troca_por = (char *)malloc(sizeof(char)*100);
272 sprintf(acha_var,"response=\"%s\"",md5_atual);
273 sprintf(troca_por,"response=\"%s\"",hex_output);
274 troca_string(pathcap,acha_var,troca_por);
275 sprintf(acha_var,"nonce=\"%s\"",nonce_atual);
276 sprintf(troca_por,"nonce=\"%s\"",sip_nonce);
277 troca_string(pathcap,acha_var,troca_por);
278 }
Fonte: o autor, 2011.
Depois do processo de autenticação, é iniciado o processo de criação do pacote a
partir do pacote armazenado no arquivo. Todos os dados dos cabeçalhos são lidos juntamente
com o payload já com as alterações dos campos SIP efetuadas.
122
Na Tabela 59 é mostrado o processo de leitura dos endereços MAC de origem e
destino salvos no arquivo. Pode ser observada na linha 315 o uso da função str2hex que
retorna o valor em formato hexadecimal da string lida do arquivo do pacote. Os números
observados à esquerda são apenas identificadores das linhas não fazendo parte do código.
Tabela 59 - Leitura dos dados do cabeçalho Ethernet. 305 sai = 0;
306 j = 0;
307 m = 0;
308 l = 0;
309 do {
310 ch = mac_src[j++];
311 if ((ch != ':') && (ch != ';')) {
312 mac_add[m] = ch;
313 m++;
314 } else {
315 ether_inj->ether_shost[l++] = str2hex(mac_add);
316 m = 0;
317 memset((char *)mac_add,'\0',sizeof(char)*3);
318 if (ch == ';')
319 sai = 1;
320 }
321 } while(sai == 0);
322
323 sai = 0;
324 j = 0;
325 m = 0;
326 l = 0;
327 do {
328 ch = mac_dst[j++];
329 if ((ch != ':') && (ch != ';')) {
330 mac_add[m] = ch;
331 m++;
332 } else {
333 ether_inj->ether_dhost[l++] = str2hex(mac_add);
334 m = 0;
335 if (ch == ';')
336 sai = 1;
337 }
338 } while(sai == 0);
Fonte: o autor, 2011.
Segue o processo de leitura e criação do pacote na Tabela 60, nas linhas 342 a 350
são lidos os dados do cabeçalho IP e UDP e nas linhas 352 a 364 esses dados são carregados
na estrutura de dados do pacote. Os números visualizados à esquerda são apenas
identificadores das linhas do arquivo não fazendo parte do código.
Tabela 60 - Leitura dos dados e criação dos cabeçalhos IP e UDP. 342 valor_string(cap_file,"IP_VER=",ip_vhl,'\n','\0');
343 valor_string(cap_file,"IP_ID=",ip_id,'\n','\0');
344 valor_string(cap_file,"IP_TTL=",ip_ttl,'\n','\0');
345 valor_string(cap_file,"IP_OFF=",ip_off,'\n','\0');
346 valor_string(cap_file,"IP_PROTO=",ip_p,'\n','\0');
347 valor_string(cap_file,"IP_SRC=",ip_src,'\n','\0');
348 valor_string(cap_file,"IP_DST=",ip_dst,'\n','\0');
349 valor_string(cap_file,"UDP_SRC=",udp_src,'\n','\0');
350 valor_string(cap_file,"UDP_DST=",udp_dst,'\n','\0');
351
352 fclose(cap_file);
353 ip_inj->ip_vhl= atoi(ip_vhl);
354 ip_inj->ip_id = htons(atoi(ip_id));
355 ip_inj->ip_ttl = atoi(ip_ttl);
356 ip_inj->ip_off = atoi(ip_off);
357 ip_inj->ip_p = atoi(ip_p);
358 ip_inj->ip_len = htons(sizeof(struct sniff_ip) + sizeof(struct
sniff_udp) + i);
123
359 inet_aton(ip_src,&ip_inj->ip_src);
360 inet_aton(ip_dst,&ip_inj->ip_dst);
361 udp_inj->uh_sport = htons(atoi(udp_src));
362 udp_inj->uh_dport = htons(atoi(udp_dst));
363 udp_inj->uh_ulen = htons(sizeof(struct sniff_udp) + i);
364 udp_len = sizeof(struct sniff_udp);
Fonte: o autor, 2011.
Depois de criado o pacote, é o momento de gerar os checksums IP e UDP. Como já
mencionado, para a geração do checksum IP é necessário apenas o cabeçalho IP mas para a
geração do checksum UDP é necessário a utilização de uma estrutura denominada psudo-
header.
A Tabela 61 mostra o desenvolvimento do processo de geração dos checksums IP e
UDP. O checksum IP é gerado nas linhas 367 e 368 utilizando apenas a estrutura do próprio
cabeçalho IP. A formação do pseudo-header inicia na linha 371 e termina na linha 376 onde
são incluídos todos os dados necessários para a geração do checksum UDP. Depois disso é
efetuada a geração do checksum nas linhas 377 a 382. Os números observados à esquerda são
apenas identificadores das linhas do arquivo não fazendo parte do código.
Tabela 61 - Geração dos checksums IP e UDP. 367 memcpy(pack_ip,(u_char *)ip_inj,sizeof(struct sniff_ip));
368 ip_inj->ip_sum = checksum(pack_ip, sizeof(struct sniff_ip));
369
370 //formação do pseudo header p/ calculo do checksum udp
371 pad_byte = 0x00;
372 memcpy(&pseudo_inj->ip_src,&ip_inj->ip_src,sizeof(u_short)*2);
373 memcpy(&pseudo_inj->ip_dst,&ip_inj->ip_dst,sizeof(u_short)*2);
374 pseudo_inj->proto = ip_inj->ip_p;
375 pseudo_inj->zero1 = 0;
376 pseudo_inj->udp_len = udp_inj->uh_ulen;
377 memcpy(pseudo+6,(u_char *)udp_inj,8);
378 memcpy(pseudo+10,payload_inj,i);
379 if (((sizeof(struct pseudo_header)+sizeof(struct sniff_udp)+i) % 2) !=
0) {
380 memcpy(pseudo+10+i,&pad_byte,sizeof(char));
381 udp_inj->uh_sum = checksum(pseudo,sizeof(struct
pseudo_header)+sizeof(struct sniff_udp)+i+1);
382 } else
383 udp_inj->uh_sum = checksum(pseudo,sizeof(struct
pseudo_header)+sizeof(struct sniff_udp)+i);
Fonte: o autor, 2011.
Após a criação do pacote e da geração dos checksums, o pacote é impresso na tela do
operador e de fato injetado. Na Tabela 62 podem ser observados os processos de impressão e
injeção. Os números observados à esquerda são apenas identificadores das linhas do arquivo e
não fazem parte do código.
Tabela 62 - Impressão do pacote e injeção. 392 imprime_pkt(pathcap);
393 handle_inj = pcap_open_live(dev,BUFSIZ,1,0,errbuf_inj);
394 sentbytes=pcap_inject(handle_inj,packet,packet_size);
395 *arq_res_cnt = *arq_res_cnt + 1;
Fonte: o autor, 2011.
No caso da comparação entre o endereço de origem IP armazenado no arquivo com o
endereço aramazenado na variável ip_orig comprovar a diferença entre esses valores, é
124
iniciado o processo de captura através da função func_escuta. Essa função é desenvolvida na
Tabela 63. Ela inicia declarando as variáveis necessárias para o processo, depois é criado o
filtro a ser aplicado na captura, a sessão de captura e por último são criadas as threads de
captura. Depois de efetuada a captura, a tarefa seguinte é a comparação entre o método SIP da
captura efetuada nesta seção com a captura na seção “Escuta”, caso os métodos sejam
diferentes, o processo de captura e injeção é paralizado.
Tabela 63 - Desenvolvimento da função func_escuta. 39 void func_escuta()
40 {
41 struct bpf_program fp;
42 char filter_exp[100];
43
44 bpf_u_int32 mask;
45 bpf_u_int32 net;
46
47 sprintf(filter_exp,"host %s and (udp src port %s or udp dst port
%s)",ip_orig,porta_dst,porta_dst);
48 pcap_lookupnet(dev, &net, &mask, errbuf_inj);
49 handle_inj = pcap_open_live(dev,BUFSIZ,1,0,errbuf_inj);
50 pcap_setnonblock(handle_inj,0,errbuf_inj);
//seta porta para não nonblock
51 pcap_compile(handle_inj, &fp, filter_exp, 0, net); //monta
filtro
52 pcap_setfilter(handle_inj, &fp);
//seta filtro
53
54 arq_pcap_nome = arq_res_nome;
55 arq_pcap_cnt = arq_res_cnt;
56
57 *stop_thread = 0;
58 pthread_create (&captThread, 0, capt,0);
59 pthread_create (&kbdThread, 0, kbd,0);
60 pthread_join (captThread, 0);
61 pthread_join (kbdThread, 0);
62
63 pcap_close(handle_inj);
64
65 //comparar o metodo SIP
66 h = *arq_res_cnt - 1;
67 if (h < 10) {
68 sprintf(pathcap,"%s0%d.cap",arq_cap_nome,h);
69 sprintf(pathcap_aux,"%s0%d.cap",arq_res_nome,h);
70 } else {
71 sprintf(pathcap,"%s%d.cap",arq_cap_nome,h);
72 sprintf(pathcap_aux,"%s%d.cap",arq_res_nome,h);
73 }
74 cap_file = fopen(pathcap,"r");
75 metodo_sip(cap_file,sip_metodo_cap_1);
76 fclose(cap_file);
77 cap_file = fopen(pathcap_aux,"r");
78 metodo_sip(cap_file,sip_metodo_cap_2);
79 fclose(cap_file);
80 if (strcmp(sip_metodo_cap_1,sip_metodo_cap_2) != 0)
81 fim = 1;
82 }
Fonte: o autor, 2011.
Semelhante ao processo de captura onde a paralização do processo pode ser feita
pelo operador, a captura da seção “Injeção” é paralizada pelo próprio processo de captura do
pacote. Dentro da função callback é setada a variável stop_thread para “1”, o laço do while da
função kbd não continua sendo executado e o comando pthread_cancel paraliza a thread de
captura capt. O desenvolvimento das threads de captura pode ser observado na Tabela 64, os
125
números visualizados à esquerda são apenas identificadores das linhas e não fazem parte do
código.
Tabela 64 - Desenvolvimento das threads de captura. 22 void* capt (void* info)
23 {
24 do {
25 pcap_dispatch(handle_inj,1,callback,NULL);
26 } while (*stop_thread == 0);
27 return (void*) 0;
28 }
29
30 void* kbd (void* info)
31 {
32 do {
33 } while (*stop_thread == 0);
34 pthread_cancel(captThread);
35
36 return (void*) 0;
37 }
Fonte: o autor, 2011.
126
4 VALIDAÇÃO DA FERRAMENTA
Para a validação da ferramenta desenvolvida foram definidos dois diferentes testes:
- Verificação dos dados capturados na da seção ”Escuta”;
- Verificação dos dados injetados e capturados na seção “Injeção”.
Ambos os testes executados utilizam as ferramentas Wireshark, Asterisk e eyeBeam
como apoio.
4.1 TOPOLOGIA UTILIZADA NA VALIDAÇÃO
Para a validação da ferramenta foi adotada uma topologia física e lógica de rede, de
forma a permitir que a troca de informações entre o dispositivo monitorado e o servidor de
comunicação Asterisk, fique a disposição do software desenvolvido e da ferramenta de apoio.
Na Figura 53 pode ser observada a topologia utilizada.
Figura 53 - Topologia utilizada na validação da ferramenta desenvolvida. Fonte: o autor, 2011.
127
A utilização do HUB como concentrador de rede se dá pela característica dele não
segmentar a rede em um domínio de colisão por porta, o domínio de colisão é o mesmo para
toda a rede. Devido a esta característica, qualquer dado que esteja passando por este
dispositivo é visível a toda a rede, permitindo a sua captura (TANENBAUM, 2003).
4.2 OBJETIVOS EM CADA TESTE
Diferentes características são analisadas em cada teste, visto que um dos testes valida
apenas a função de captura da ferramenta enquanto o outro valida as funções de captura e
injeção em conjunto.
4.2.1 Teste de Validação de Captura
No teste de validação de captura efetuada na seção “Escuta”, o objetivo é verificar se
a ferramenta é capaz de capturar todos os dados da interoperabilidade do SIP entre o
dispositivo monitorado e o servidor Asterisk e se os dados capturados e armazenados são
íntegros. Assume-se para este teste que o tráfego total da interoperabilidade do SIP é o tráfego
capturado e mostrado pela ferramenta Wireshark, que os pacotes capturados e mostrados pelo
Wireshark são íntegros e possuem uma construção correta, e portanto, a integridade dos dados
capturados é obtida através da comparação entre os dados capturados pelo software
desenvolvido e os dados capturados pela ferramenta Wireshark.
4.2.2 Teste de Validação de Captura e Injeção
No teste de validação de captura e injeção efetuados na seção “Injeção”, o objetivo é
verificar se a ferramenta é capaz de capturar todos os dados da interoperabilidade do SIP entre
o dispositivo monitorado e o servidor Asterisk, se os dados capturados e armazenados estão
128
íntegros, se a construção dos pacotes está sendo feita de forma correta e se é capaz de
sincronizar a injeção e a captura dos pacotes de forma a permitir que a interoperabilidade do
SIP seja entre a ferramenta desenvolvida e o servidor Asterisk. Assume-se para este teste que
o tráfego total da interoperabilidade do SIP é o tráfego capturado e mostrado pela ferramenta
Wireshark, que os pacotes capturados e mostrados pelo Wireshark são íntegros e possuem
uma construção correta, e portanto a integridade dos dados capturados é obtida através da
comparação entre os dados capturados pelo software desenvolvido e os dados capturados pela
ferramenta Wireshark, e que o relatório de interoperabilidade do SIP disponibilizado pelo
Wireshark seja o que está realmente acontecendo entre os dispositivos em questão.
129
5 RESULTADOS E CONCLUSÕES
Neste capítulo são mostrados os resultados dos testes efetuados para a validação da
ferramenta juntamente com a conclusão a respeito da proposta.
5.1 RESULTADOS OBTIDOS DO TESTE DE CAPTURA
Este teste visa verificar se todos os pacotes da interoperabilidade do SIP entre os
dispositivos foram capturados pelo software desenvolvido na seção “Escuta” e se os dados
capturados e armazenados são íntegros. Para que o teste seja realizado é gerado um evendo,
neste evento o dispositivo SIP de identificação 200 tenta estabelecer uma sessão multimídia
com o usuário 300 que não está autenticado no servidor no momento da tentativa.
Na Figura 54 pode-se visualizar a seção “Dados Escutados” que mostra todos os
pacotes capturados juntamente com os valores dos campos SIP detectados. São visualizados
sete pacotes capturados, pode-se verificar a detecção dos campos na coluna “ESCUTA”. O
usuário que tentou efetuar o estabelecimento da sessão multimídia identificado como 200, e o
usuário o qual foi convidado para sessão multimídia identificado como 300. Pode-se verificar
também o username utilizado na autenticação do usuário 200 que é o próprio número do
usuário. A password como já mencionado, não é possível detectar na captura dos pacotes.
130
Figura 54 - Seção "Dados Escutados". Fonte: o autor, 2011.
Já na Figura 55 pode-se verificar os dados capturados pelo Wireshark. Podem ser
visualizados também sete pacotes capturados. Se comparados aos capturados pelo software
desenvolvido, pode-se afirmar que todos os pacotes foram capturados com sucesso.
Figura 55 - Pacotes capturados pelo Wireshark. Fonte: o autor, 2011.
Na Tabela 65 pode-se observar o pacote 01 capturado pelo software desenvolvido
enquanto na Figura 56 pode-se observar o mesmo pacote capturado pelo Wireshark. Constata-
se através dessas duas imagens, a integridade dos dados capturados pelo software
desenvolvido uma vez que todos os campos dos cabeçalhos foram identificados e
armazenados de maneira correta.
Tabela 65 - Pacote 01 capturado pelo software desenvolvido. 1 ARQ_NUM=01
2
3 ETHER_MAC_SRC=0:C:29:68:26:3A;
4 ETHER_MAC_DST=0:C:29:41:58:95;
5 ETHER_TYPE=8
6
131
7 IP_VER=69
8 IP_TOS=0
9 IP_LEN=746
10 IP_ID=1374
11 IP_OFF=0
12 IP_TTL=128
13 IP_PROTO=17
14 IP_CHK=28497
15 IP_SRC=192.168.33.2
16 IP_DST=192.168.33.1
17
18 UDP_SRC=8304
19 UDP_DST=5060
20 UDP_LEN=726
21 UDP_CHK=12546
22
23 INVITE sip:[email protected] SIP/2.0
24 To: <sip:[email protected]>
25 From: TCC 200<sip:[email protected]>;tag=66064d22
26 Via: SIP/2.0/UDP 192.168.33.2:8304;branch=z9hG4bK-d87543-127761736-1--d87543-;rport
27 Call-ID: 4c15ae004b318627
28 CSeq: 1 INVITE
29 Contact: <sip:[email protected]:8304>
30 Max-Forwards: 70
31 Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
32 Content-Type: application/sdp
33 User-Agent: eyeBeam release 3004w stamp 16863
34 Content-Length: 235
35
36 v=0
37 o=- 56250259 56250343 IN IP4 192.168.33.2
38 s=eyeBeam
39 c=IN IP4 192.168.33.2
40 t=0 0
41 m=audio 8306 RTP/AVP 0 8 18 101
42 a=alt:1 1 : DCFAF33A 4E58F998 192.168.33.2 8306
43 a=fmtp:101 0-15
44 a=rtpmap:101 telephone-event/8000
45 a=sendrecv
Fonte: o autor, 2011.
Figura 56 - Pacote 01 capturado pelo Wireshark. Fonte: o autor, 2011.
132
5.2 RESULTADOS OBTIDOS DO TESTE DE CAPTURA E INJEÇÃO
Este teste visa verificar se todos os pacotes da interoperabilidade do SIP entre os
dispositivos foram capturados pelo software desenvolvido na seção “Injeção”. Neste teste o
dispositivo SIP de identificação 200 tenta estabelecer uma sessão multimídia com o usuário
300 que não está autenticado no servidor no momento da tentativa. Porém, a injeção será
efetuada alterando a identificação do usuário convidado para 500.
A Figura 57 mostra a seção “Dados Escutados” com todos os pacotes capturados na
seção “Escuta” e com os campos do SIP detectados. Nota-se que o usuário convidado para a
sessão multimídia detectado na “Escuta” é diferente do que será utilizado na “Injeção”. No
caso, o operador efetuou a alteração desse campo do SIP além de incluir a password do
usuário 200 que é quem está tentando estabelecer a sessão multimídia. Essa senha foi
mencionada anteriormente na configuração do Asterisk que é utilizado como ferramenta de
apoio para este teste. A senha deve ser incluída para que ocorra a autenticação do usuário SIP
uma vez que não é possível detectar a senha na captura dos pacotes e a chave criptografada
varia em cada nova sessão multimídia a ser estabelecida.
Figura 57 - Seção "Dados Escutados". Fonte: o autor, 2011.
A Figura 58 mostra a seção “Injeção” e os pacotes que foram capturados e injetados.
133
Figura 58 - Seção "Injeção". Fonte: o autor, 2011.
Na Figura 59 pode-se verificar a seção “Mostrar Resultados” onde visualizam-se os
pacotes da seção “Escuta” e da seção “Injeção”.
Figura 59 - Seção "Mostrar Resultados". Fonte: o autor, 2011.
Na Figura 60 pode-se visualizar os pacotes capturados pelo Wireshark.
134
Figura 60 - Pacotes capturados pelo Wireshark. Fonte: o autor, 2011.
Nota-se que os pacotes capturados pelo Wireshark não coincidem com os capturados
e/ou injetados pelo software. Pode-se perceber primeiramente no Wireshark, que o servidor
enviou dois pacotes resposta com o status 401 Unauthorized que significa a solicitação da
autenticação. No analisador, apenas um pacote com o status 401 Unauthorized pode ser
visualizado. Com base nessa comparação, pode-se afirmar que o analisador não capturou um
dos pacotes. Ao final do fluxo de mensagens, no Wireshark podem ser observados vários
pacotes com o status 404 Not Found enquanto no analisador apenas um pacote com as
mesmas características pode ser observado. Nesse caso, o analisador parou a captura pois a
resposta contida no pacote de sequência cinco capturado na seção “Injeção” difere da resposta
contida no pacote de sequência cinco capturado na seção “Escuta”, portanto trata-se de uma
situação prevista no software.
Não se pode afirmar de fato o que está ocorrendo, mas pode-se afirmar que a
ferramenta consegue gerenciar o sincronismo entre os pacotes enviados e recebidos. Nota-se
que ocorre praticamente da mesma maneira a interoperabilidade entre os dispositivos. Em
uma análise superficial do problema, é possível verificar que o software está perdendo um
pacote no momento da captura na seção “Injeção” pelo fato de estar no momento processando
o pacote a ser injetado. Esta situação poderia a vir ocorrer uma vez que o analisador possui
todos os pacotes a serem injetados armazenados em um disco rígido cujo acesso pode
demandar mais tempo do que a própria resposta do servidor SIP.
A Tabela 66 mostra o pacote 02 capturado pelo software desenvolvido.
Tabela 66 - Pacote 02 capturado pelo software. 1 ARQ_NUM=02
2
3 ETHER_MAC_SRC=0:C:29:41:58:95;
4 ETHER_MAC_DST=0:C:29:68:26:3A;
5 ETHER_TYPE=8
6
7 IP_VER=69
8 IP_TOS=0
9 IP_LEN=532
135
10 IP_ID=62754
11 IP_OFF=0
12 IP_TTL=64
13 IP_PROTO=17
14 IP_CHK=49250
15 IP_SRC=192.168.33.1
16 IP_DST=192.168.33.2
17
18 UDP_SRC=5060
19 UDP_DST=8304
20 UDP_LEN=512
21 UDP_CHK=28863
22
23 SIP/2.0 401 Unauthorized
24 Via: SIP/2.0/UDP 192.168.33.2:8304;branch=z9hG4bK-d87543-127761736-1--d87543-
;received=192.168.33.2;rport=8304
25 From: TCC 200<sip:[email protected]>;tag=66064d22
26 To: <sip:[email protected]>;tag=as054b9133
27 Call-ID: 4c15ae004b318627
28 CSeq: 1 INVITE
29 Server: Asterisk PBX 1.6.2.11
30 Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO
31 Supported: replaces, timer
32 WWW-Authenticate: Digest algorithm=MD5, realm="asterisk", nonce="5255188f"
33 Content-Length: 0
Fonte: o autor, 2011.
A Figura 61 mostra o pacote 02 capturado pelo Wireshark.
Figura 61 - Pacote 02 capturado pelo Wireshark. Fonte: o autor, 2011.
Analisando os dados dos pacotes capturados, pode-se afirmar que o pacote capturado
e armazenado pelo software desenvolvido está íntegro.
136
5.3 CONCLUSÃO
O trabalho apresentou como proposta o desenvolvimento de um analisador SIP capaz
de efetuar a captura, alteração e injeção dos pacotes relacionados a interoperabilidade do SIP
de forma a proporcionar uma análise a respeito da interoperabilidade que ocorre entre os
dispositivos SIP. As principais tarefas determinadas para o desenvolvimento foram concluídas
com sucesso, alguns problemas foram detectados mas serão tratados no aperfeiçoamento da
ferramenta.
Dentre as informações contidas neste trabalho pode-se destacar:
a) Detalhamento da captura e de um pacote da rede de dados;
b) Detalhamento dos campos dos cabeçalhos, Ethernet, IP e UDP;
c) Detalhamento do cálculo do checksum IP e do checksum UDP;
d) Detalhamento da autenticação do protocolo SIP com uso de um algoritmo MD5;
e) Detalhamento da conformação de um pacote;
f) Detalhamento da injeção de um pacote na rede de dados.
Observando a quantidade de informações, pode-se afirmar que o trabalho pode servir
como base de conhecimento para futuras implementações na área de redes digitais. Portanto, a
principal contribuição que fica além do estímulo à análise do protocolo SIP, é o conjunto de
informações a respeito do tratamento de pacotes capturados e/ou injetados em uma rede de
dados. Também fica como contribuição uma ferramenta que se aperfeiçoada, pode ser
utilizada como apoio na solução de problemas relacionados a interoperabilidade do protocolo
SIP.
Do ponto de vista do cenário de telecomunicações nos dias de hoje, pode-se afirmar
que o tema aqui apresentado é de grande importância frente a unificação das redes de
comunicação e a expansão dos serviços sobre essas redes. Este tema é atual e possui bastante
valor agregado.
137
5.4 SUGESTÃO PARA TRABALHOS FUTUROS
As sugestões para trabalhos futuros seguem duas linhas de raciocínio. A primeira
está relacionada ao aperfeiçoamento da ferramenta criada, visando resolver os problemas
detectados e a sua qualidade em relação a interface com o operador. A segunda linha está
relacionada com a expansão da ferramenta para análises não previstas neste projeto.
Conhecendo um pouco do protocolo estudado, pode-se afirmar que existem muitos caminhos
a serem seguidos neste sentido.
5.4.1 Aperfeiçoamento da Ferramenta
Percebidas as deficiências da ferramenta, pode-se afirmar que primeiramente devem
ser corrigidos alguns problemas detectados no processo de validação como a perda de alguns
pacotes na etapa captura, injeção e sincronismo. Talvez pelo fato de estar se trabalhando com
o dispositivo de armazenamento, o processo de leitura dos dados armazenados pode estar
demandando um tempo alto o que acaba comprometendo a agilidade da ferramenta. Portanto
uma das melhorias sugeridas seria uma análise quanto ao desempenho da ferramenta.
Outra melhoria sugerida seria na linha de interface com o operador, visto que estão
disponíveis hoje bibliotecas que auxiliam na criação de interface gráfica para softwares
baseados em plataforma Linux, seria interessante criar uma interface mais amigável com o
operador ao invés de utilizar apenas menus baseados em texto puro. Essa melhoria pode
ajudar a difundir o uso da ferramenta no caso da disponibilização da mesma.
5.4.2 Continuidade da Proposta
Visto que apenas alguns campos do protocolo SIP foram disponibilizados para
alteração em apenas um método, e sabendo da complexidade do protocolo, é interessante
continuar a proposta no sentido de expandir a análise do protocolo. Essa expansão se daria no
138
sentido de disponibilizar mais campos do SIP para serem alterados além de disponibilizar a
análise de outros métodos do protocolo.
139
REFERÊNCIAS BIBLIOGRÁFICAS
ABZUG, M. T. MD5 Homepage (unofficial). UMBC, 1991. Disponivel em:
<http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html>. Acesso em: 05 Junho 2011.
BALBINOT, R. Modelagem e Prototipagem de Sistemas de Voz Sobre IP com
Mecanismos de Trasmissão Robusta. Dissertação de Mestrado. [S.l.]: Faculdade de
Engenharia PUCRS, 2002.
CAMARILLO, G. SIP Demystified. [S.l.]: McGraw-Hill, 2002. ISBN 0-07-137340-3.
CARSTENS, T. Programming with pcap. TCPDump & LibPcap, 2002. Disponivel em:
<http://www.tcpdump.org/pcap.html>. Acesso em: 13 Abril 2011.
CASADO, M. Packet Capture With libpcap and other Low Level Network Tricks.
Washington State University - The School of Electrical Engineering and Computer
Science, 2001. Disponivel em: <http://eecs.wsu.edu/~sshaikot/docs/lbpcap/libpcap-
tutorial.pdf>. Acesso em: 14 Abril 2011.
CISCO. Voice Over IP, Per Call Bandwidth Comsuption. Cisco Systems, 2006. Disponivel
em:
<http://www.cisco.com/en/US/tech/tk652/tk698/technologies_tech_note09186a0080094ae2.s
html>. Acesso em: 22 Junho 2010.
COUNTERPATH. eyeBeam - Datasheet. CounterPath, 2011. Disponivel em:
<http://www.counterpath.com>. Acesso em: 7 Junho 2011.
CPLUSPLUS. cplusplus.com, 2011. Disponivel em: <http://www.cplusplus.com/>. Acesso
em: 10 Junho 2011.
DAVIDSON, J. VoIP Fundamentals. Tradução de Ricardo Balbinot. 2ª. ed. [S.l.]: Bookman,
2008. ISBN 978-85-7780-113-8.
ECLIPSE. Eclipse documentation - Helios. Eclipse, 2011. Disponivel em:
<http://help.eclipse.org/helios/index.jsp>. Acesso em: 7 Junho 2011.
GOLENIEWSKI, L. Telecommunications Essentials, Second Edition: The Complete
Global Source. 2ª. ed. [S.l.]: Addison Wesley Professional, 2006. ISBN 978-0-321-42761-8.
140
HALSALL, F. Computer Networking and the Internet. 5ª. ed. [S.l.]: Addison Wesley
Professional, 2005. ISBN 0-321-26358-8.
JACOBSON, V.; LERES, C.; MCCANNE, S. PCAP, C Library Functions. TCPDump &
LibPcap, 2003. Disponivel em: <http://www.tcpdump.org/pcap3_man.html>. Acesso em: 14
Novembro 2010.
JACOBSON, V.; LERES, C.; MCCANNE, S. Filtering expression syntax. Berkeley National
Laboratory - University of California, 2008. Disponivel em:
<http://www.manpagez.com/man/7/pcap-filter/>. Acesso em: 27 Maio 2011.
JOHNSTON, A. B. SIP: Understanding the Session Initiation Protocol. 3ª. ed. [S.l.]: Artech
House, 2009. ISBN 978-1-60783-995-8.
KRIVUTSENKO'S, A. Digest authorization in SIP with MD5. Persistent notes, 2006.
Disponivel em: <http://alexkr.com/memos/66/digest-authorization-in-sip-with-md5/>. Acesso
em: 23 Maio 2011.
LAMPING, U.; SHARPE, R.; WARNICKE, E. Wireshark User's Guide: for Wireshark 1.7.
Wireshark, 2011. Disponivel em: <http://www.wireshark.org>. Acesso em: 25 Maio 2011.
MADSEN, L.; MEGGELEN, J. V.; BRYANT, R. Asterisk: The Definitive Guide. 3ª. ed.
[S.l.]: O‟Reilly Media, 2011.
MCGANN, S.; SICKER, D. C. An Analysis of Security Threats and Tools in SIP-Based
VoIP Systems. [S.l.]: University of Colorado, 2005.
ROSENBERG, J. RFC3261 - SIP: Session Initiation Protocol. Internet Engineering Task
Force. [S.l.]. 2002.
STEVENS, W. R. TCP/IP Illustrated: The Protocols. 1ª. ed. [S.l.]: Addison Wesley, v. I,
1993. ISBN 0201633469.
TANENBAUM, A. S. Computer Networks. 4ª. ed. [S.l.]: Prentice Hall, 2003. ISBN 0-13-
066102-3.
TCPDUMP. Latest Release. TCPDump & LibPcap, 2011. Disponivel em:
<http://www.tcpdump.org/#>. Acesso em: 15 Maio 2011.
WALL, K.; WATSON, M.; WHITIS, M. Linux Programming Unleashed. [S.l.]: Sams,
1999. ISBN 0-672-31607-2.
WALLINGFORD, T. Switching to VoIP. [S.l.]: O'Reilly, 2005. ISBN 0-596-00868-6.
141
ANEXO A – Código para geração do Checksum utilizado nos cabeçalhos IP e UDP
Tabela 67 - Código para geração do checksum. 1 /*
2 * Copyright (c) 1998-2006 The TCPDUMP project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * miscellaneous checksumming routines
16 *
17 * Original code by Hannes Gredler ([email protected])
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24
25 /*
26 * Creates the OSI Fletcher checksum. See 8473-1, Appendix C, section C.3.
27 * The checksum field of the passed PDU does not need to be reset to zero.
28 */
29 u_short checksum(u_short *ptr, int length){
30 register int sum = 0;
31 u_short answer = 0;
32 register u_short *w = ptr;
33 register int nleft = length;
34
35 while(nleft > 1){
36 sum += *w++;
37 nleft -= 2;
38 }
39
40 sum = (sum >> 16) + (sum & 0xFFFF);
41 sum += (sum >> 16);
42 answer = ~sum;
43 return(answer);
44 }
Fonte: (TCPDUMP, 2011)
Os números visualizados à esquerda são apenas identificadores das linhas não
fazendo parte do código.
142
ANEXO B – Código para geração do hash MD5 utilizado no SIP
Tabela 68 - Código utilizado para a geração do hash MD5. 1 /*
2 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 L. Peter Deutsch
22
23 */
24 /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
25 /*
26 Independent implementation of MD5 (RFC 1321).
27
28 This code implements the MD5 Algorithm defined in RFC 1321, whose
29 text is available at
30 http://www.ietf.org/rfc/rfc1321.txt
31 The code is derived from the text of the RFC, including the test suite
32 (section A.5) but excluding the rest of Appendix A. It does not include
33 any code or documentation that is identified in the RFC as being
34 copyrighted.
35
36 The original and principal author of md5.c is L. Peter Deutsch
37 <[email protected]>. Other authors are noted in the change history
38 that follows (in reverse chronological order):
39
40 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
41 either statically or dynamically; added missing #include <string.h>
42 in library.
43 2002-03-11 lpd Corrected argument list for main(), and added int return
44 type, in test program and T value program.
45 2002-02-21 lpd Added missing #include <stdio.h> in test program.
46 2000-07-03 lpd Patched to eliminate warnings about "constant is
47 unsigned in ANSI C, signed in traditional"; made test program
48 self-checking.
49 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
50 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
51 1999-05-03 lpd Original version.
52 */
53
54 #include "md5.h"
55 #include <string.h>
56
57 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
58 #ifdef ARCH_IS_BIG_ENDIAN
59 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
60 #else
61 # define BYTE_ORDER 0
62 #endif
63
64 #define T_MASK ((md5_word_t)~0)
143
65 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
66 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
67 #define T3 0x242070db
68 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
69 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
70 #define T6 0x4787c62a
71 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
72 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
73 #define T9 0x698098d8
74 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
75 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
76 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
77 #define T13 0x6b901122
78 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
79 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
80 #define T16 0x49b40821
81 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
82 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
83 #define T19 0x265e5a51
84 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
85 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
86 #define T22 0x02441453
87 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
88 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
89 #define T25 0x21e1cde6
90 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
91 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
92 #define T28 0x455a14ed
93 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
94 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
95 #define T31 0x676f02d9
96 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
97 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
98 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
99 #define T35 0x6d9d6122
100 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
101 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
102 #define T38 0x4bdecfa9
103 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
104 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
105 #define T41 0x289b7ec6
106 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
107 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
108 #define T44 0x04881d05
109 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
110 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
111 #define T47 0x1fa27cf8
112 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
113 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
114 #define T50 0x432aff97
115 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
116 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
117 #define T53 0x655b59c3
118 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
119 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
120 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
121 #define T57 0x6fa87e4f
122 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
123 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
124 #define T60 0x4e0811a1
125 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
126 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
127 #define T63 0x2ad7d2bb
128 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
129
130
131 static void
132 md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
133 {
134 md5_word_t
135 a = pms->abcd[0], b = pms->abcd[1],
136 c = pms->abcd[2], d = pms->abcd[3];
137 md5_word_t t;
138 #if BYTE_ORDER > 0
139 /* Define storage only for big-endian CPUs. */
140 md5_word_t X[16];
141 #else
144
142 /* Define storage for little-endian or both types of CPUs. */
143 md5_word_t xbuf[16];
144 const md5_word_t *X;
145 #endif
146
147 {
148 #if BYTE_ORDER == 0
149 /*
150 * Determine dynamically whether this is a big-endian or
151 * little-endian machine, since we can use a more efficient
152 * algorithm on the latter.
153 */
154 static const int w = 1;
155
156 if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
157 #endif
158 #if BYTE_ORDER <= 0 /* little-endian */
159 {
160 /*
161 * On little-endian machines, we can process properly aligned
162 * data without copying it.
163 */
164 if (!((data - (const md5_byte_t *)0) & 3)) {
165 /* data are properly aligned */
166 X = (const md5_word_t *)data;
167 } else {
168 /* not aligned */
169 memcpy(xbuf, data, 64);
170 X = xbuf;
171 }
172 }
173 #endif
174 #if BYTE_ORDER == 0
175 else /* dynamic big-endian */
176 #endif
177 #if BYTE_ORDER >= 0 /* big-endian */
178 {
179 /*
180 * On big-endian machines, we must arrange the bytes in the
181 * right order.
182 */
183 const md5_byte_t *xp = data;
184 int i;
185
186 # if BYTE_ORDER == 0
187 X = xbuf; /* (dynamic only) */
188 # else
189 # define xbuf X /* (static only) */
190 # endif
191 for (i = 0; i < 16; ++i, xp += 4)
192 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
193 }
194 #endif
195 }
196
197 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
198
199 /* Round 1. */
200 /* Let [abcd k s i] denote the operation
201 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
202 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
203 #define SET(a, b, c, d, k, s, Ti)\
204 t = a + F(b,c,d) + X[k] + Ti;\
205 a = ROTATE_LEFT(t, s) + b
206 /* Do the following 16 operations. */
207 SET(a, b, c, d, 0, 7, T1);
208 SET(d, a, b, c, 1, 12, T2);
209 SET(c, d, a, b, 2, 17, T3);
210 SET(b, c, d, a, 3, 22, T4);
211 SET(a, b, c, d, 4, 7, T5);
212 SET(d, a, b, c, 5, 12, T6);
213 SET(c, d, a, b, 6, 17, T7);
214 SET(b, c, d, a, 7, 22, T8);
215 SET(a, b, c, d, 8, 7, T9);
216 SET(d, a, b, c, 9, 12, T10);
217 SET(c, d, a, b, 10, 17, T11);
218 SET(b, c, d, a, 11, 22, T12);
145
219 SET(a, b, c, d, 12, 7, T13);
220 SET(d, a, b, c, 13, 12, T14);
221 SET(c, d, a, b, 14, 17, T15);
222 SET(b, c, d, a, 15, 22, T16);
223 #undef SET
224
225 /* Round 2. */
226 /* Let [abcd k s i] denote the operation
227 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
228 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
229 #define SET(a, b, c, d, k, s, Ti)\
230 t = a + G(b,c,d) + X[k] + Ti;\
231 a = ROTATE_LEFT(t, s) + b
232 /* Do the following 16 operations. */
233 SET(a, b, c, d, 1, 5, T17);
234 SET(d, a, b, c, 6, 9, T18);
235 SET(c, d, a, b, 11, 14, T19);
236 SET(b, c, d, a, 0, 20, T20);
237 SET(a, b, c, d, 5, 5, T21);
238 SET(d, a, b, c, 10, 9, T22);
239 SET(c, d, a, b, 15, 14, T23);
240 SET(b, c, d, a, 4, 20, T24);
241 SET(a, b, c, d, 9, 5, T25);
242 SET(d, a, b, c, 14, 9, T26);
243 SET(c, d, a, b, 3, 14, T27);
244 SET(b, c, d, a, 8, 20, T28);
245 SET(a, b, c, d, 13, 5, T29);
246 SET(d, a, b, c, 2, 9, T30);
247 SET(c, d, a, b, 7, 14, T31);
248 SET(b, c, d, a, 12, 20, T32);
249 #undef SET
250
251 /* Round 3. */
252 /* Let [abcd k s t] denote the operation
253 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
254 #define H(x, y, z) ((x) ^ (y) ^ (z))
255 #define SET(a, b, c, d, k, s, Ti)\
256 t = a + H(b,c,d) + X[k] + Ti;\
257 a = ROTATE_LEFT(t, s) + b
258 /* Do the following 16 operations. */
259 SET(a, b, c, d, 5, 4, T33);
260 SET(d, a, b, c, 8, 11, T34);
261 SET(c, d, a, b, 11, 16, T35);
262 SET(b, c, d, a, 14, 23, T36);
263 SET(a, b, c, d, 1, 4, T37);
264 SET(d, a, b, c, 4, 11, T38);
265 SET(c, d, a, b, 7, 16, T39);
266 SET(b, c, d, a, 10, 23, T40);
267 SET(a, b, c, d, 13, 4, T41);
268 SET(d, a, b, c, 0, 11, T42);
269 SET(c, d, a, b, 3, 16, T43);
270 SET(b, c, d, a, 6, 23, T44);
271 SET(a, b, c, d, 9, 4, T45);
272 SET(d, a, b, c, 12, 11, T46);
273 SET(c, d, a, b, 15, 16, T47);
274 SET(b, c, d, a, 2, 23, T48);
275 #undef SET
276
277 /* Round 4. */
278 /* Let [abcd k s t] denote the operation
279 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
280 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
281 #define SET(a, b, c, d, k, s, Ti)\
282 t = a + I(b,c,d) + X[k] + Ti;\
283 a = ROTATE_LEFT(t, s) + b
284 /* Do the following 16 operations. */
285 SET(a, b, c, d, 0, 6, T49);
286 SET(d, a, b, c, 7, 10, T50);
287 SET(c, d, a, b, 14, 15, T51);
288 SET(b, c, d, a, 5, 21, T52);
289 SET(a, b, c, d, 12, 6, T53);
290 SET(d, a, b, c, 3, 10, T54);
291 SET(c, d, a, b, 10, 15, T55);
292 SET(b, c, d, a, 1, 21, T56);
293 SET(a, b, c, d, 8, 6, T57);
294 SET(d, a, b, c, 15, 10, T58);
295 SET(c, d, a, b, 6, 15, T59);
146
296 SET(b, c, d, a, 13, 21, T60);
297 SET(a, b, c, d, 4, 6, T61);
298 SET(d, a, b, c, 11, 10, T62);
299 SET(c, d, a, b, 2, 15, T63);
300 SET(b, c, d, a, 9, 21, T64);
301 #undef SET
302
303 /* Then perform the following additions. (That is increment each
304 of the four registers by the value it had before this block
305 was started.) */
306 pms->abcd[0] += a;
307 pms->abcd[1] += b;
308 pms->abcd[2] += c;
309 pms->abcd[3] += d;
310 }
311
312 void
313 md5_init(md5_state_t *pms)
314 {
315 pms->count[0] = pms->count[1] = 0;
316 pms->abcd[0] = 0x67452301;
317 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
318 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
319 pms->abcd[3] = 0x10325476;
320 }
321
322 void
323 md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
324 {
325 const md5_byte_t *p = data;
326 int left = nbytes;
327 int offset = (pms->count[0] >> 3) & 63;
328 md5_word_t nbits = (md5_word_t)(nbytes << 3);
329
330 if (nbytes <= 0)
331 return;
332
333 /* Update the message length. */
334 pms->count[1] += nbytes >> 29;
335 pms->count[0] += nbits;
336 if (pms->count[0] < nbits)
337 pms->count[1]++;
338
339 /* Process an initial partial block. */
340 if (offset) {
341 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
342
343 memcpy(pms->buf + offset, p, copy);
344 if (offset + copy < 64)
345 return;
346 p += copy;
347 left -= copy;
348 md5_process(pms, pms->buf);
349 }
350
351 /* Process full blocks. */
352 for (; left >= 64; p += 64, left -= 64)
353 md5_process(pms, p);
354
355 /* Process a final partial block. */
356 if (left)
357 memcpy(pms->buf, p, left);
358 }
359
360 void
361 md5_finish(md5_state_t *pms, md5_byte_t digest[16])
362 {
363 static const md5_byte_t pad[64] = {
364 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
368 };
369 md5_byte_t data[8];
370 int i;
371
372 /* Save the length before padding. */
147
373 for (i = 0; i < 8; ++i)
374 data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
375 /* Pad to 56 bytes mod 64. */
376 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
377 /* Append the length. */
378 md5_append(pms, data, 8);
379 for (i = 0; i < 16; ++i)
380 digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
381 }
Fonte: (ABZUG, 1991)
Os números visualizados à esquerda são apenas identificadores das linhas não
fazendo parte do código.
148
ANEXO C – Código para organização dos bits na criação do pacote
Tabela 69 - Código para organização dos bits na criação do pacote. 1 /*
2 * Copyright (c) 1992, 1993, 1994, 1995, 1996
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * @(#) $Header: /var/repositorio/20110507_captura_sip/src/extract.h,v 1.1 2011/05/08
12:55:03 gio Exp $ (LBL)
22 */
23
24 /*
25 * Macros to extract possibly-unaligned big-endian integral values.
26 */
27 #ifdef LBL_ALIGN
28 /*
29 * The processor doesn't natively handle unaligned loads.
30 */
31 #ifdef HAVE___ATTRIBUTE__
32 /*
33 * We have __attribute__; we assume that means we have __attribute__((packed)).
34 * Declare packed structures containing a u_int16_t and a u_int32_t,
35 * cast the pointer to point to one of those, and fetch through it;
36 * the GCC manual doesn't appear to explicitly say that
37 * __attribute__((packed)) causes the compiler to generate unaligned-safe
38 * code, but it apppears to do so.
39 *
40 * We do this in case the compiler can generate, for this instruction set,
41 * better code to do an unaligned load and pass stuff to "ntohs()" or
42 * "ntohl()" than the code to fetch the bytes one at a time and
43 * assemble them. (That might not be the case on a little-endian platform,
44 * where "ntohs()" and "ntohl()" might not be done inline.)
45 */
46 typedef struct {
47 u_int16_t val;
48 } __attribute__((packed)) unaligned_u_int16_t;
49
50 typedef struct {
51 u_int32_t val;
52 } __attribute__((packed)) unaligned_u_int32_t;
53
54 #define EXTRACT_16BITS(p) \
55 ((u_int16_t)ntohs(((const unaligned_u_int16_t *)(p))->val))
56 #define EXTRACT_32BITS(p) \
57 ((u_int32_t)ntohl(((const unaligned_u_int32_t *)(p))->val))
58 #define EXTRACT_64BITS(p) \
59 ((u_int64_t)(((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 0)->val))
<< 32 | \
60 ((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 1)->val)) <<
0))
61
149
62 #else /* HAVE___ATTRIBUTE__ */
63 /*
64 * We don't have __attribute__, so do unaligned loads of big-endian
65 * quantities the hard way - fetch the bytes one at a time and
66 * assemble them.
67 */
68 #define EXTRACT_16BITS(p) \
69 ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | \
70 (u_int16_t)*((const u_int8_t *)(p) + 1)))
71 #define EXTRACT_32BITS(p) \
72 ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | \
73 (u_int32_t)*((const u_int8_t *)(p) + 1) << 16 | \
74 (u_int32_t)*((const u_int8_t *)(p) + 2) << 8 | \
75 (u_int32_t)*((const u_int8_t *)(p) + 3)))
76 #define EXTRACT_64BITS(p) \
77 ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 0) << 56 | \
78 (u_int64_t)*((const u_int8_t *)(p) + 1) << 48 | \
79 (u_int64_t)*((const u_int8_t *)(p) + 2) << 40 | \
80 (u_int64_t)*((const u_int8_t *)(p) + 3) << 32 | \
81 (u_int64_t)*((const u_int8_t *)(p) + 4) << 24 | \
82 (u_int64_t)*((const u_int8_t *)(p) + 5) << 16 | \
83 (u_int64_t)*((const u_int8_t *)(p) + 6) << 8 | \
84 (u_int64_t)*((const u_int8_t *)(p) + 7)))
85 #endif /* HAVE___ATTRIBUTE__ */
86 #else /* LBL_ALIGN */
87 /*
88 * The processor natively handles unaligned loads, so we can just
89 * cast the pointer and fetch through it.
90 */
91 #define EXTRACT_16BITS(p) \
92 ((u_int16_t)ntohs(*(const u_int16_t *)(p)))
93 #define EXTRACT_32BITS(p) \
94 ((u_int32_t)ntohl(*(const u_int32_t *)(p)))
95 #define EXTRACT_64BITS(p) \
96 ((u_int64_t)(((u_int64_t)ntohl(*((const u_int32_t *)(p) + 0))) << 32 | \
97 ((u_int64_t)ntohl(*((const u_int32_t *)(p) + 1))) << 0))
98 #endif /* LBL_ALIGN */
99
100 #define EXTRACT_24BITS(p) \
101 ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 16 | \
102 (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \
103 (u_int32_t)*((const u_int8_t *)(p) + 2)))
104
105 /*
106 * Macros to extract possibly-unaligned little-endian integral values.
107 * XXX - do loads on little-endian machines that support unaligned loads?
108 */
109 #define EXTRACT_LE_8BITS(p) (*(p))
110 #define EXTRACT_LE_16BITS(p) \
111 ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | \
112 (u_int16_t)*((const u_int8_t *)(p) + 0)))
113 #define EXTRACT_LE_32BITS(p) \
114 ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 3) << 24 | \
115 (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \
116 (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \
117 (u_int32_t)*((const u_int8_t *)(p) + 0)))
118 #define EXTRACT_LE_24BITS(p) \
119 ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \
120 (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \
121 (u_int32_t)*((const u_int8_t *)(p) + 0)))
122 #define EXTRACT_LE_64BITS(p) \
123 ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 7) << 56 | \
124 (u_int64_t)*((const u_int8_t *)(p) + 6) << 48 | \
125 (u_int64_t)*((const u_int8_t *)(p) + 5) << 40 | \
126 (u_int64_t)*((const u_int8_t *)(p) + 4) << 32 | \
127 (u_int64_t)*((const u_int8_t *)(p) + 3) << 24 | \
128 (u_int64_t)*((const u_int8_t *)(p) + 2) << 16 | \
129 (u_int64_t)*((const u_int8_t *)(p) + 1) << 8 | \
130 (u_int64_t)*((const u_int8_t *)(p) + 0)))
Fonte: (TCPDUMP, 2011)
Os números visualizados à esquerda são apenas identificadores das linhas não
fazendo parte do código.