Ping - C

Started by Dark_Side, 23 de December , 2006, 12:57:18 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dark_Side

Hi,

Sem idéias para meus últimos tópicos, desta vez irei postar um programinha, escrito em C, que utiliza a DLL ICMP.DLL para executar um ping em um host.

Basicamente, o programa obtém, externamente, os endereços das funções dentro da DLL: IcmpCreateFile, IcmpCloseHandle e IcmpSendEcho.

Com a função IcmpCreateFile, iniciamos o serviço PING, após preenchermos as estruturas e parâmetros que cada função externa exige, chamamos, através de ponteiros, a função IcmpSendEcho - que irá executar efetivamente o ping.

Após executado, devemos utilizar a função IcmpCloseHandle para finalizar o serviço.

Para facilitar, mative alguns parâmetros encontrados no ping do Windows:

Quote-t              = envia pacotes constatemente;
-l tamanho = especifica o tamanho dos pacotes: 0 a 65500 bytes;
-n num      = define o número de pacotes
-i TTL        = define o tempo de vida: 0 a 255;
-s TOS       = define o tipo de serviço: 1 a 4.

Segue abaixo o source (compile-o linkando a lib "wsock32"):
 
ping.c
#include <stdio.h>    // Entrada e saída padronizadas
#include <stdlib.h>   // Alocação dinâmica, conversões, etc
#include <windows.h>  // Constantes e funções da API do Windows
#include <winsock.h>  // Header do winsock
#include "funcoes.h"  // Header com funções, constantes, variáveis e estruturas do código

// Declaração de funções
void pingar(struct ping_args *);
int  enviar_pacote(void);
void envia_infinitos(void);
void envia_num(unsigned long);

// Função principal
int main(int argn, char * arg[]){

    system("cls"); // Limpa a tela
     if(argn < 2)  // Verifica argumentos
     {
             puts("Uso:  ping HOST [-t] [-l tamanho] [-n numero] [-i TTL] [-s TOS]\n");
             puts("Opcoes");
             puts("      -t \t                Envia pacotes infinitos.");
             puts("      -l tamanho \t        Define o tamanho dos pacotes.");
             puts("      -n numero  \t        Define a quantidade de pacotes.");
             puts("      -i TTL     \t        Define o tempo de vida.");
             puts("      -s TOS     \t        Define o tipo de servico.\n");
             
             system("pause");
             return 1;
             }
             
     // Limpa estrutura
     memset(&ping_arg,0x0,sizeof(struct ping_args));
     
     // Define parâmetros iniciais
     ping_arg.infinitos = FALSE; // NÃO enviar pacotes infinitamente
     ping_arg.tam       = 256;   // Tamanho do buffer a enviar
     ping_arg.num       = 4;     // Número de pacotes
     ping_arg.tos       = 1;     // Tipo de serviço
     ping_arg.ttl       = 128;   // Tempo de vida
     
     
     obter_parametros(argn,arg); // Obtém argumentos e atualiza os parâmetros acima
       
     if(WSAStartup(0x101,&wsa) ==-1){ // Tenta inicializar winsock -> usar gethostbyname()
      puts("Erro ao inicializar Winsock");
      exit(1);}
     
     // Tenta resolver host
     host = gethostbyname(HOST_ARG);
     if(!host){
        printf("Ocorreu um erro ao resolver o host: %s",HOST_ARG);
        exit(1);}

     addr = *(unsigned long*)host->h_addr; // Transforma-o em network byte
     
     inicializar();             // Inicializa ICMP
     
     if(ping_arg.tam > 65500)   // Verifica se o tamanho do pacote ultrapassa 65.500 Bytes
       ping_arg.tam = 256;      // Reinicia o valor inicial
       
     cria_buffer(ping_arg.tam); // Cria buffer do pacote
     pingar(&ping_arg);         // Inicia o ping


    FecharICMP(PING_ID);    // Termina o ping
    free(ping_buffer);      // Libera buffer alocado
    free(PingResp);         // Libera estrutura alocada
    FreeLibrary(icmp_dll);  // Libera DLL
    WSACleanup();           // Finaliza Winsock

return 0;
}


// Função para pingar
void pingar(struct ping_args * parametros)
{
ip_host   = inet_ntoa(*(struct in_addr*)&addr); // Obtém IP do host
nome_host = host->h_name;                       // Obtém hostname

system("cls"); // Limpa a tela

if(parametros->tos > 4)   // Se TOS for maior do que 4 (inválido) -> reinicia-o
 parametros->tos = 1;
 
if(parametros->ttl > 255) // Se TTL for maior do que 255 (inválido) -> reinicia-o
 parametros->tos = 128;

// Ajusta parâmetros
PingResp->opcoes.tos = parametros->tos;
PingResp->opcoes.ttl = parametros->ttl;


if(parametros->infinitos == TRUE) // Verifica se a opção -t foi utilizada
 envia_infinitos();
else
 envia_num(parametros->num);      // Se -t não foi utilizada, envia o número de pacotes (-n numero)

}

void envia_infinitos()
{
     
  while(1){
  Sleep(600); 

  if(!enviar_pacote()) // Envia o pacote
     puts("Tempo limite esgotado."); // Retorno 0 = erro
  else{                              // Retorno 1 = resposta recebida

   printf("Resposta de %s [%s]:\n\n",ip_host,nome_host);  // Mostra IP e HostName
   printf("tempo(sec) = %lu\n",(PingResp->tempo / 1000)); // Mostra tempo de resposta (segundos)
   printf("TTL        = %lu\n",PingResp->opcoes.ttl);     // Mostra tempo de vida
   printf("Bytes      = %lu\n\n",PingResp->tam_data);     // Mostra número de bytes
      }
}
}

void envia_num(unsigned long num)
{
 
int i=0;

 while(i < num){ // Enquanto o número de pacotes definido não for atingido
 Sleep(600);

  // Envia o pacote e filtra retorno
  if(!enviar_pacote())
     puts("Tempo limite esgotado.");
  else{

   printf("Resposta de %s [%s]:\n\n",ip_host,nome_host);  // Mostra IP e HostName
   printf("tempo(sec) = %lu\n",(PingResp->tempo / 1000)); // Mostra tempo de resposta (segundos)
   printf("TTL        = %lu\n",PingResp->opcoes.ttl);     // Mostra tempo de vida
   printf("Bytes      = %lu\n\n",PingResp->tam_data);     // Mostra número de bytes
     }   
  i++; // Incrementa número de pacotes
     
}
}

int enviar_pacote()
{
  // Envia o pacote ICMP retornando o valor da função externa
  return EnviarICMP(PING_ID,addr,ping_buffer,ping_arg.tam,NULL,PingResp,PingResp_Tam + ping_arg.tam,1);
}

[b]funcoes.h[/b]

// Abaixo temos estruturas, constantes, variáveis e funções globais

// Opções do pacote
struct ping_opt{
unsigned char ttl;      // Tempo de vida
unsigned char tos;      // Tipo de serviço
unsigned char flags;    // IP header flags
unsigned char op_tam;   // Tamanho do buffer de dados opcionais
unsigned char * op_dados; // Dados opcionais
};

// Resposta do Ping
struct ping_resp{
unsigned long   addr;       // Endereço de resposta
unsigned long   status;     // Reply status
unsigned long   tempo;      // Tempo de resposta
unsigned short  tam_data;   // Tamanho do buffer -> enviar no ping
unsigned short  reservado;  // Reservado para o sistema
char *          buffer;     // Ponteiro para o buffer
struct ping_opt opcoes;     // Estrutura ping_opt -> opções do pacote
};

// Argumentos
struct ping_args{
BOOL           infinitos;  // Pacotes infinitos
unsigned long  tam;        // Tamanho do buffer
unsigned long  num;        // Número de pacotes
unsigned short tos;        // Tipo de serviço
unsigned short ttl;        // Tempo de vida
};


// Tamanho da estrutura ping_resp
#define PingResp_Tam sizeof(struct ping_resp)

// Declaração de estruturas
struct ping_opt    PingOp;
struct ping_resp * PingResp;
struct ping_args   ping_arg;

// Define ponteiros para funções
typedef HANDLE (WINAPI* pfnCriar) (void);
typedef BOOL   (WINAPI* pfnFechar)(HANDLE);
typedef DWORD  (WINAPI* pfnEnviar)(HANDLE, DWORD, LPVOID, WORD,struct ping_opt*, LPVOID, DWORD, DWORD);

// Declaração dos ponteiros
pfnCriar  CriarICMP;
pfnFechar FecharICMP;
pfnEnviar EnviarICMP;


HINSTANCE icmp_dll; // Handle para a DLL
HANDLE PING_ID; // ID do ping

// Variáveis do winsock
WSADATA wsa;
struct hostent * host = NULL;

// Ponteiros para char
char * ip_host;
char * nome_host;
char * ping_buffer;
char * HOST_ARG;

unsigned long addr; // Endereço alvo em network byte

// Declaração de funções
void inicializar(void);
void cria_buffer(unsigned long);
void obter_parametros(int,char**);
void erro_arg(const char*);     


// Inicialização
void inicializar()
{
     // Carrega dinamicamente a DLL
    icmp_dll = LoadLibrary("ICMP.DLL");
    if(!icmp_dll){
       puts("Ocorreu um erro ao abrir a dll "ICMP.DLL".");
       exit(1);}

     // Obtém endereços remotos de cada função da DLL
     CriarICMP  = (pfnCriar)GetProcAddress(icmp_dll,"IcmpCreateFile");
     FecharICMP = (pfnFechar)GetProcAddress(icmp_dll,"IcmpCloseHandle");
     EnviarICMP = (pfnEnviar)GetProcAddress(icmp_dll,"IcmpSendEcho");

     // Verifica validade dos endereços
     if(!CriarICMP || !FecharICMP || !EnviarICMP) {
        puts("Ocorreu um erro ao obter as funcoes externas.");
        exit(1);}
 
     PING_ID = CriarICMP(); // Cria um novo ping (lolz)
     if(PING_ID == (HANDLE)-1){ // Verifica
        puts("Ocorreu um erro ao inicializar o ping.");
        exit(1);}
}


void cria_buffer(unsigned long tam)     // Aloca buffer utilizado no pacote
{
     ping_buffer = (char*)malloc(tam);  // Aloca espaço no buffer
     memset(ping_buffer,0x61,tam);      // Preenche-o com o caractere 'A'
   
     PingResp = (struct ping_resp*)malloc(PingResp_Tam + tam); // Aloca estrutura
     
     if(!PingResp){
        puts("Erro ao alocar espaco na estrutura PingResp");
         exit(1);}
     
     // Ajusta parâmetros
     PingResp->buffer   = ping_buffer; // Ponteiro para o buffer
     PingResp->tam_data = tam;         // Tamanho do buffer
     
}

// Verifica argumentos
void obter_parametros(int argn, char ** argumento)
{
     int i,x;
     char * arg;
     char arg_lista[5][3] = {"-t","-l","-n","-i","-s"}; // Lista de argumentos
     
     // Primeiro argumento = alvo do ping
     HOST_ARG = argumento[1];

     for(i=1;i<argn;i++)   // Pecorre os argumentos
     {
          arg = argumento[i];
          for(x=0;x<5;x++){
            if(!strcmp(arg,arg_lista[x])){ // Verifica se o argumento coincide com um parâmetro
             
               if(i==1) // Valida alvo
                    erro_arg("Especifique um Host!");   

              switch(x){
                   case 0: // -t
                        ping_arg.infinitos = TRUE;
                        break;

                   case 1: // -l tamanho
                        if(i+1 > argn || argumento[i+1] == NULL)
                           erro_arg("Digite um tamanho valido!");
                         else
                            ping_arg.tam = atol(argumento[i+1]); 
                         break;
                         
                         
                   case 2: // -n numero
                        if(i+1 > argn || argumento[i+1] == NULL)
                           erro_arg("Digite um numero valido!");
                         else
                            ping_arg.num = atol(argumento[i+1]);
                         break;
                         
                   case 3: // -i TTL
                        if(i+1 > argn || argumento[i+1] == NULL)
                           erro_arg("Digite um TTL valido!");
                         else
                            ping_arg.ttl = (u_short)atol(argumento[i+1]); 
                         break;

                   case 4: // -s TOS
                        if(i+1 > argn || argumento[i+1] == NULL)
                           erro_arg("Digite um TOS valido!");
                         else
                            ping_arg.tos = (u_short)atol(argumento[i+1]); 
                         break;
                           }
                           
                   break;
            }}}
}

// Erro de argumento
void erro_arg(const char* msg)
{
     printf("%s\n",msg);
     exit(1);
}



Para finalizar, seguem o código e o executável:

Arquivo em Anexo - Security Ðarkers - wWw.darkers.com.br

Bye ;)