Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.
Conexões Multithreaded
IP/Port Scan e técnicas de otimização
Você já deve ter ouvido falar em um IP scan ou um Port scan. Basicamente eles têm a função de encontrar em uma rede IPs que estejam com uma determinada porta aberta, e encontrar todas as portas abertas em um determinado IP, respectivamente. Ao longo deste artigo, demonstraremos a implementação de um utilitário com esse propósito.
Visão geral
Desenvolveremos nosso aplicativo dividindo-o em três partes bem definidas, são elas: o "kernel", um componente e a interface gráfica. No kernel, residirá a parte mais interessante de nosso código – ele encapsula uma thread responsável por realizar a conexão. O componente fica encarregado de gerenciar as threads, de acordo com as configurações especificadas, além de notificar a interface gráfica o estado atual de seu trabalho. A interface, por sua vez, exemplificará o uso do componente criado apresentando informações sobre o andamento do processo.
Nosso aplicativo poderá ser utilizado para os mais variados fins. Poderemos usá-lo, por exemplo, para descobrir quais máquinas numa rede são servidores FTP. Para isso, basta que façamos uma pesquisa pelos hosts que estão com a porta 21 aberta, por exemplo. Ainda podemos verificar o comportamento de algum aplicativo suspeito, colocá-lo em execução e verificar se ele abriu alguma nova porta. Poderíamos listar muitas outras possibilidades...
Metodologia
Para verificar se uma determinada porta está aberta, apenas tentaremos nos conectar a ela. Caso a conexão seja estabelecida, contabilizaremos um sucesso; caso contrário, uma exceção será levantada e tratada.
Muitas vezes existe uma dificuldade em identificar se uma aplicação deve ou não utilizar múltiplas threads. Nesse exemplo, veremos a vantagem da dividir o processamento em várias threads – o uso de apenas uma imporia uma grande perda de tempo, pois as tentativas de conexão teriam de esperar "em fila". Essa é a chave do processo: como não há dependências entre as conexões, podemos fazê-las em paralelo, aumentando o desempenho da aplicação.
O kernel
O "kernel", a parte principal da aplicação, é a classe TScan. Para iniciar o exemplo, faça o seguinte: caso o Delphi esteja aberto clique em File | Close All. Crie um novo pacote no Delphi, clicando em File|New|Other>Package (salve-o como “pkScan.dpk”), crie uma unit e salve-a como “untScan.pas”. Veja o conteúdo da unit na Listagem 1.
Listagem 1. untScan.pas
unit untScan;
interface
uses
Classes, SysUtils, SyncObjs, StdCtrls,
IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient;
type
TFoundEvent = procedure (Source : TObject; const IP : String;
const Porta : Integer) of object;
TThreadTerminate = TNotifyEvent;
TScan = class(TThread)
private
FSkt : TIdTCPClient;
FTimeOut : Integer;
FFoundEvent : TFoundEvent;
FFimEvent : TThreadTerminate;
procedure DoFim;
procedure Fim(Sender : TObject);
procedure DoConnect(Sender: TObject);
protected
procedure Execute; override;
public
constructor CreateSetting
(FoundEvent : TFoundEvent; FimEvent : TThreadTerminate;
const IP : String; const Porta, TimeOut : Longint);
property TimeOut : Integer read FTimeOut write FTimeOut;
end;
implementation
constructor TScan.CreateSetting
(FoundEvent : TFoundEvent; FimEvent : TThreadTerminate;
const IP: String; const Porta, TimeOut: Integer);
...