26 de abril de 2010

Recuperando a lista de adaptadores de um computador em Delphi

Em maio de 2009, bem no início desse blog, postei um texto chamado Obtendo o MAC Address para gerar um Hardware Key em Delphi, onde eu recuperava o MAC Address do adaptador de rede para gerar um código único a ser usado para liberar o licenciamento de um produto qualquer. Os trechos de programa incluídos naquele post permitiam recuperar apenas o primeiro adaptador, ignorando a existência de outros.

Enviaram-me, então, uma situação (veja aqui) em que o uso de um adaptador bluetooth instalado na USB modifica a ordem com que os adaptadores são listados. A pergunta decorrente desse cenário é como garantir que a chave gerada será sempre a mesma, sem termos que ficar na dependência da ordem com que os adaptadores são listados?

No exemplo do outro post, usei a função GetAdaptersInfo da API do Windows mas não mostrei como percorrer a lista de adaptadores. Essa função popula uma estrutura do tipo IP_ADAPTER_INFO com informações relativas a um único adaptador por vez. A estrutura IP_ADAPTER_INFO é na verdade uma lista ligada, sendo que as informações para a estrutura seguinte podem ser acessadas através do campo Next. Quando esse campo está prenchido com o valor Nil, significa que não há mais adaptadores na lista:
var i : integer;
pAdapterInfo : PIP_ADAPTER_INFO;
begin
{ ... }
repeat
{ Processa informações do adaptador atualmente posicionado }
for i := 0 to MAX_ADAPTER_ADDRESS_LENGTH - 1 do
Result[i] := pAdapterInfo.Address[i];

pAdapterInfo := pAdapterInfo.Next;
until (pAdapterInfo = Nil);
{ ... }
No trecho acima eu não mostro a chamada à função GetAdaptersInfo, que inicia as informaçõe em pAdapterInfo - veja aqui uma explicação de como fazer isso.

A ideia de percorrer toda a lista de adaptadores é que agora podemos aplicar o cálculo do código de identificação do licenciamento mostrado no outro post usando cada um dos MAC Address listados até que um deles gere o código correto ou que o fim da lista seja atingido.

Uma forma de minimizar o problema seria restringir a lista de adaptadores, verificando-lhes o tipo - se é um adaptador Ethernet, SLIP, PPP, Token Ring, etc. Essa informação é colocada no campo Type_ da estrutura IP_ADAPTER_INFO; os valores possíveis para esse campo estão na documentação encontrada no MSDN.

Segue uma função completa capaz de obter os adaptadores e percorrer a lista. Adaptadores do tipo Token Ring são desconsiderados pelo programa:
procedure ListaMACaddress;
varAdapterInfo : Pointer;
pAdapterInfo : PIP_ADAPTER_INFO;
dwBufLen, dwStatus : LongWord;
begin
dwBufLen := 0;
AdapterInfo := Nil;

GetAdaptersInfo(PIP_ADAPTER_INFO (AdapterInfo), dwBufLen);
if (dwBufLen > 0) then begin
GetMem (AdapterInfo, dwBufLen);
dwStatus := GetAdaptersInfo(PIP_ADAPTER_INFO (AdapterInfo), dwBufLen);

if (dwStatus = ERROR_SUCCESS) then begin
pAdapterInfo := PIP_ADAPTER_INFO (AdapterInfo);

repeat
{ Processa informações do adaptador atualmente posicionado }
if (pAdapterInfo.Type_ <> MIB_IF_TYPE_TOKENRING) then
TrataAdaptador (pAdapterInfo);

{ Próximo adaptador da lista }
pAdapterInfo := pAdapterInfo.Next;
until (pAdapterInfo = Nil);

FreeMem (AdapterInfo);
end;
end;
end;
A função TrataAdaptador não está listada nesse trecho mas seu objetivo é representar uma operação qualquer em cima dos dados de um adaptador.

4 comentários :

Anônimo disse...

mtu bom...
gostaria de saber se tem como eu identificar todos os macs, tipo eu busco os bluetooths disponiveis e ele ja me apresenta o mac de todos a ponto de poder manipula-los meu intuito é consegui-los e bloquea-los para não mandar mensagens repetidas por exemplo ou com curto intervalo
meg-lim@hotmail.com
grata

Luís Gustavo Fabbro disse...

Talvez não tenha ficado claro no texto, mas ao percorrer a lista de adaptadores do computador temos em mãos uma estrutura do tipo IP_ADAPTER_INFO com todas as informações relativas a um adpatador, um de cada vez. O MAC Address associado a ele está no campo Address da estrutura.

Anônimo disse...

Estou pesquisando sobre MAC e encontrei o blog, muito bom por sinal.
O problema que tenho que resolver é uma aplicação abrindo uma porta socket qualquer. Quando um Client se conectar a esta porta, tenho que verificar se o Macaddress desta conexão está dentro do meu ranger de MAC. Caso seja libero a conexão.
A solução que tenho hoje é gerando uma tabela ARP no formato TXT depois vou lendo as linhas deste arquivo montando dentro da aplicação um controle. Quando chega um pedido de conexão veja na minha tabela e faço a liberção. O ruim é que se não estiver na minha tabela tenho que gerar outra e etc...
Nesta solução apresentada existe uma maneira de pegar o MAC dentro do protocolo TCP ou mesmo acessar diretamente a tabela ARP do Windows?

Luís Gustavo Fabbro disse...

O que vai no post é apenas um método para recuperar o MAC local, independentemente do tipo de comunicação que se queira fazer na rede.

O que você precisa é mais complexo. Dê uma olha na discussão existente nesse forum :
http://under-linux.org/f143/mikrotik-x-delphi-102136/

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.