Introdução

 

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

edileioliveira@hotmail.com

 

 

 

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

 

p>

/* 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.

ss=MsoBodyText> 

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.