\n'; document.write(barra); } } changePage();
Apresentação | Código Fonte | Modelagem | Winsock
Implementação de
uma ferramenta de monitoração de tráfego de rede TCP/IP usando Winsock
Edilei Marcos de Oliveira
1 Introdução
2 A ferramenta de monitoração
3 Modelo em camadas TCP/IP
4 A biblioteca Winsock
5 Decodificação dos datagramas IP
6 Apresentação da ferramenta de monitoração
7 Conclusão
1 Introdução
O objetivo principal deste artigo é apresentar as rotinas da Winsock necessárias para a implementação de uma ferramenta de monitoração de tráfego de rede TCP/IP em uma rede ETHERNET. Esta ferramenta de monitoração trabalha com a captura, decodifição e cópia dos datagramas IPv4 em buffer, obedecendo às regras de captura definidas em filtro. Para a captura de pacotes, exige-se que o dispositivo de comunicação, onde a ferramenta está instalada, seja configurado para operar em modo promíscuo, isto é, o dispositivo de comunicação aceita todos os pacotes de rede que estiverem transitando pelo segmento de rede diretamente conectado ao dispositivo. Para colocar o dispositivo de comunicação para operar em modo promíscuo no Windows, usa-se um driver de captura externo, de terceiros, ou usa-se um socket configurado para operar em modo promíscuo através das rotinas da Winsock 2.2 sobre Windows 2000 ou superior. Ferramentas como TCPDUMP e ETHEREAL utilizam driver de captura externo para rodarem, porém, a partir do Windows 2000, pode-se usar a API Winsock 2.2 ou superior do próprio sistema operacional para capturar os pacotes TCP/IP. Os códigos aqui apresentados estão em C++ sobre o ambiente Visual C++ 6.0.
2 A ferramenta de monitoração
Através da análise dos pacotes TCP/IP capturados da rede, o administrador de rede pode gerenciar melhor sua rede, pela análise dos pacotes ICMP, realizar mapeamento das conexões TCP/IP de um determinado host, pela análise de tráfego originado ou destinado a determinado host, verificar níveis de segurança, observando se há dados secretos que não estão sendo criptografados, descobrir os serviços (SMTP, DNS, FTP, HTTP e outros) que os hosts da rede ETHERNET oferecem ou requisitam.
Como o domínio de captura pode ser muito amplo, uma maneira de restringi-lo é estabelecer regras de filtragem, que podem ser por tipo de protocolo ou por porta de comunicação. Desta forma, a análise fica concentrada aos pacotes que safisfazem as regras do filtro.
As seguintes etapas são realizadas pela ferramenta:
1. captura do pacote;
2. decodifica pacote;
3. compara pacote capturado com as definições do filtro de pacotes;
4. se o pacote não satisfazer as regras do filtro de pacotes, o pacote será ignorado;
5. se o pacote satisfazer as regras do filtro de pacotes, a ferramenta copia o pacote em buffer;
6.
continua a captura até encher o buffer ou, se antes
disso, o usuário solicitar o término da captura.
3 Modelo em camadas TCP/IP
Existem dois modelos dominantes sobre a divisão dos protocolos em camadas. O primeiro foi proposto pela ISSO, é conhecido como modelo OSI composto por 7 camadas. O segundo modelo, mais adequado a realidade, designa que a pilha de protocolos TCP/IP (tabela 1) é composta por 4 camadas ou níveis: aplicação, transporte, rede, física.
|
Aplicação HTTP, SMTP, POP3, DNS, FTP, SNMP, DHCP, telnet, EGP e outros |
Mensagens |
Protocolos usados pelos programas aplicativos. Os programas aplicativos passam as mensagens apropriadas ao protocolo de transporte para transmissão. |
|
Transporte TCP, UDP |
Pacotes ou mensagens |
TCP: protocolo de transferência confiável, com conexão e com controle de fluxo. UDP: protocolo de transferência de mensagens não confiável, com conexão e sem controle de fluxo. |
|
Rede IP, ICMP |
Datagramas IP |
IP: protocolo de roteamento, sem conexão. ICMP: é parte do datagrama IP, protocolo para deteção de erros de rede usado por hosts e roteadores. |
|
Física Drivers de dispositivo e protocolos de acesso ao meio |
Quadros de rede |
Os protocolos da camada física recebem e transmitem os datagramas IP através da rede conectada. |
Tabela 1 Camadas TCP/IP
Na perspectiva da ferramenta de monitoração, o diagrama 1 ilustra o relacionamento entre os protocolos. O socket em modo promíscuo recebe o datagrama IP, representado em dois campos: cabeçalho e área de dados. O cabeçalho do datagrama IP possui um campo

Diagrama 1 Relacionamento entre os
protocolos TCP/IP
que indica qual pacote (TCP, UDP, ICMP) está encapsulado em sua área de dados e outro campo que especifica o tamanho do cabeçalho em palavras de 32 bits, permitindo determinar o início da área de dados do datagrama. Os pacotes TCP ou UDP contêm um cabeçalho e podem conter uma área de dados (alguns pacotes não possuem área de dados porque transportam somente as informações de controle). Os cabeçalhos dos pacotes TCP e UDP possuem campos de porta de origem e porta de destino que identificam os programas aplicativos nas extremidades da conexão, um campo de comprimento do cabeçalho TCP em palavras de 32 bits que permite determinar o ínicio da área de dados quando existir.
4 A biblioteca Winsock
Todas as operações de recebimento de datagramas IP serão realizadas através de chamadas às rotinas da Winsock 2.2 , que é uma biblioteca do Windows que provê recursos de comunicação de dados. Antes que comecemos utilizar a biblioteca Winsock, nós devemos declarar o cabeçalho: #include <winsock2.h> e importar a biblioteca ws2_32.lib. O trecho de código abaixo inicializa a biblioteca para uso.
/*armazena informações sobre a inicialização da Winsock */
WSAData info;
WORD versao;
versao= MAKEWORD(2,2);
/*inicialização da biblioteca WS2_32.DLL versão 2.2*/
if (WSAStartup(versao, &info) != 0) {
MessageBox(NULL, "A inicialização da Winsock falhou!", "WSAStartup", MB_OK);
}
A rotina WSAStartup serve para inicializar a biblioteca Winsock. O parâmetro versao informa a versão da biblioteca requisitada e o parâmetro info obtém informações sobre a biblioteca inicializada.
Depois de terminar de usar a biblioteca Winsock a aplicação deverá chamar a rotina WSACleanup para desregistrar a biblioteca WS2_32.DLL e liberar os recursos alocados para ela.
/* libera recursos da biblioteca alocada */
WSACleanup();
Após a inicialização da biblioteca Winsock é executada a criação de um socket.
/*criação do socket */
sd =
socket(AF_INET, SOCK_RAW, IPPROTO_IP);
O primeiro argumento (AF_INET) da função socket especifica que o protocolo a ser usado pelo socket pertence a família TCP/IP. O segundo argumento (SOCK_RAW) especifica que os datagramas IP podem encapsular qualquer tipo de protocolo, inclusive protocolos que estão em fase experimental. O terceiro argumento (IPPROTO_IP) especifica o protocolo IP. A função socket retorna um descritor de socket.
Depois da criação do socket é necessário configurá-lo através da função bind. O primeiro argumento da função bind é o descritor de socket para a captura dos pacotes. Para o segundo argumento, passa-se o endereço da variável interfaceRecepcao do tipo SOCKADDR_IN, que contém as informações de endereço IP da interface utilizada na captura, a família de protocolos (TCP/IP) e a porta de operação, e realiza-se um cast com a estrutura SOCKADDR. O terceiro argumento é o comprimento da variável interfaceRecepcao.
A função WSAIoctl é usada para configurar o socket ou para retornar parâmetros operacionais associados ao socket. No caso, usamos a palavra SIO_RCVALL para configurar o socket em modo promíscuo que habilita o socket receber todos datagramas IP da rede. Privilégios de administrador são exigidos sobre o computador local para configurar este socket. SIO_RCVALL está disponível em Windows 2000 ou superior. O comando SIO_RCVALL antes de ser usado deve ser definido como: #define SIO_RCVALL WSAIOW(IOC_VENDOR,1).
...
SOCKADDR_IN interfaceRecepcao; // configurações para o socket
/* configuração da interface de recepção */
/* endereço IP da inferface de captura */
interfaceRecepcao.sin_addr.S_un
= enderecoIp.S_un;
/* comunicação TCP/IP */
interfaceRecepcao.sin_family
= AF_INET;
interfaceRecepcao.sin_port = htons(0);
/* associa o endereço IP da interface de captura ao
socket */
if (bind(sd, (SOCKADDR *) &interfaceRecepcao, sizeof(interfaceRecepcao))==SOCKET_ERROR)
{
wsprintf(mensagem,"bind()
falhou. Código de erro: %d",WSAGetLastError());
MessageBox(NULL,"Função
bind() falhou","Aviso!",MB_OK);
return 0;
}
int comprimentoBufferEntrada;
comprimentoBufferEntrada = 1;
/*configura o socket para modo promíscuo */
if (WSAIoctl(sd,
SIO_RCVALL,&comprimentoBufferEntrada,
sizeof(comprimentoBufferEntrada),NULL,0,&bytesRetorno,NULL,
NULL) == SOCKET_ERROR)
{
wsprintf(mensagem,
"WSAIoctl(SIO_RCVALL) falhou. Código de erro: %d",
WSAGetLastError());
MessageBox(NULL,"Função
WSAIoctl() falhou","Aviso!",MB_OK);
return
0;
}
...
Devemos chamar a função WSARecv para receber o datagrama IP através do socket. O primeiro argumento da função WSARecv é o descritor de socket que foi configurado para modo promíscuo. O segundo argumento é um ponteiro para um array de estrutura WSABUF. Cada estrutura WSABUF possui um ponteiro para um buffer e o comprimento do buffer em bytes. O terceiro argumento está informando que o array de WSABUF possui tamanho um. O quarto argumento é um ponteiro para um número que armazena o número de bytes recebidos após a chamada WSARecv se completar.
...
char
mensagem[100];
unsigned long
comprimento;
unsigned long flags;
flags=0;
comprimento=0;
/* recebe os pacotes na estrutura wsabuf */
if (SOCKET_ERROR==WSARecv(sd,wsabuf, 1, &comprimento, &flags, NULL, NULL)) {
wsprintf(mensagem, "WSARecv() falhou. Código de erro: %d",WSAGetLastError());
MessageBox(NULL, mensagem,
"Problema no recebimento!", MB_OK);
return 0;
}
wsabuf->len=comprimento;
...
5 Decodifição dos datagramas IP
Logo após que a chamada WSARecv se complete apropriadamente o sistema começa a realizar a decodificação parcial do datagrama IP, que consiste numa seqüência de bits brutos, para verificar se o pacote atende as regras de filtragem. Caso o pacote atenda as regras do filtro, ele é bufferizado, senão é descartado. Este processo de captura e decodificação, repete-se até que o buffer esteja cheio ou o usuário interrompa o processo de captura.
Como o pacote recebido sempre é um datagrama IP, a decodificação se inicia pela análise dos campos do seu cabeçalho que contém informações sobre o protocolo que sua área de dados transporta. Desencapsula-se o datagrama IP e se avalia o protocolo que está nele contido, começando-se pela análise dos campos do seu cabeçalho que contém informações sobre o possível protocolo contido em sua área de dados. Esta análise continua até chegarmos ao protocolo do nível de aplicação.
O diagrama 2 apresenta as classes de decodificação dos protocolos IP, TCP, UDP e ICMP (só o cabeçalho comum entre os vários tipos de mensagens ICMP) em notação UML. A relação de dependência das classes de decodificação TCP, UDP e ICMP com a classe IP, é considerada devido ao contexto de decodificação.
Após a chamada à função WSARecv se completar adequadamente, vamos decodificar parcialmente o datagrama IP que está no buffer em uma estrutura do tipo WSABUF. Primeiramente decodificamos apenas alguns campos importantes para defrontarmos com as regras de filtragem dos pacotes. O trecho de código a seguir são métodos para a decodificação parcial do datagrama IP pertencentes à classe de decodificação CDatagramaIP.
...
/* recebe o datagrama IP em formato bruto para
decodicação */
void
CDatagramaIP::decodificarParcialmenteDatagramaIP(WSABUF *wsabuf)
{
versao_e_comprimento
= (BYTE) wsabuf->buf[0];
tamanhoTotal
= (BYTE) wsabuf->buf[2]*256 + (BYTE) wsabuf->buf[3];
protocolo
= (BYTE) wsabuf->buf[9];
ipOrigem
= (BYTE) wsabuf->buf[12]*16777216 +
(BYTE) wsabuf->buf[13]*65536 +
(BYTE) wsabuf->buf[14]*256 +
(BYTE) wsabuf->buf[15];
ipDestino = (BYTE) wsabuf->buf[16]*16777216 +
(BYTE) wsabuf->buf[17]*65536 +
(BYTE) wsabuf->buf[18]*256 +
(BYTE) wsabuf->buf[19];
/* dados do datagrama IP*/
dados.len=tamanhoTotal
- obterTamanhoCabecalho();
dados.buf=&wsabuf->buf[obterTamanhoCabecalho()];
}
/* obtém o tamanho do cabecalho em bytes */
unsigned char CDatagramaIP::obterTamanhoCabecalho()
{
unsigned char aux;
aux =
versao_e_comprimento;
/*determina os valores dos
4 bits menos significativos */
aux = aux & 15;
return aux*4;
}
/* obtém tamanho total do datagrama IP
unsigned short CDatagramaIP::obterTamanhoTotal()
{
return
tamanhoTotal;
}
/* obtém código do protocolo encapsulado no
datagrama IP
int CDatagramaIP::obterCodigoProtocolo()
{
return
protocolo;
}
/* obtém o endereço IP de destino do datagrama no
formato de um número inteiro */
unsigned int CDatagramaIP::obterIpDestinoNumerico()
{
return
ipDestino;
}
/* obtém o endereço IP de origem do datagrama no
formato de um número inteiro */
unsigned int CDatagramaIP::obterIpOrigemNumerico()
{
return
ipOrigem;
}
/* obtém os dados do datagrama IP */
WSABUF CDatagramaIP::obterDadosIP()
{
return
dados;
}
...

6 Apresentação da ferramenta de monitoração
A figura 1 mostra um conjunto de datagramas IP capturados da rede e que contém em um comum a string “rnp” em sua área de dados. O pacote de número 22, que está em foco, por exemplo, tem 1500 bytes de tamanho, ensapsula os protocolos TCP e HTTP, foi transmido do host 200.130.9.7 usando a porta de conexão 80 (serviço HTTP) para o host 200.186.215.183 na porta de conexão 1249. Podemos verificar na área de dados do pacote, que se trata de um texto legível, isto é, sem criptografia da informação.

Figura 1 Tela da ferramenta contendo pacotes capturados
7 Conclusão
Este artigo teve como foco a apresentação das primitivas da API Winsock
2.2 para criação e uso de um socket em modo promíscuo para desenvolvimento de
uma ferramenta de monitoração do tráfego de rede TCP/IP sobre uma rede
ETHERNET. A avaliação do tráfego de rede permite: gerenciar melhor a rede,
verificar níveis de segurança, mapear conexões e descobrir os serviços
oferecidos ou utilizados pela rede.
BIBLIOGRAFIA
COMER, Douglas E; STEVENS, David L. Internetworking with TCP/IP – Vol. III. New Jersey: Editora
Prentice-Hall, 1997.
COMER, Douglas E; STEVENS,
David L. Interligação Em Rede Com
Tcp/Ip – Vol. I. Rio de Janeiro:
Editora Campus, 1998.
Livraria da
Microsoft. URL: http://msdn.microsoft.com/library. Acessada em 01/09/2002.
\n'; document.write(barra); } } changePage();
URL: http://www.securityfriday.com/Topics/caputure_packet.html. Acessada em 22/04/2002.
RFC 768. User Datagram Protocol. URL: http://www.ietf.org. Acessada em 22/04/2002
RFC 791. Internet Protocol. URL: http://www.ietf.org. Acessada em 22/04/2002.
RFC 792. Internet Control Messagem Protocol. URL: http://www.ietf.org. Acessada em 22/04/2002.
RFC 793. Transmission
Control Protocol. URL: http://www.ietf.org. Acessada em 22/04/2002.