Protocolo ICMP

A classe asio::ip::icmp é uma classe em C++ que faz parte da biblioteca Asio (Asynchronous Input/Output) e é usada para implementar a comunicação usando o protocolo ICMP (Internet Control Message Protocol).

O protocolo ICMP é um protocolo de nível de rede que é usado para enviar mensagens de erro e de controle entre dispositivos de rede. Ele é comumente usado para testar a conectividade entre dispositivos de rede, como o comando ping em sistemas operacionais.

A classe asio::ip::icmp fornece uma interface para criar e gerenciar sockets ICMP. Ela é usada para criar sockets ICMP, que são usados para enviar e receber mensagens ICMP. Ela também fornece métodos para enviar e receber mensagens ICMP através de um socket, bem como para gerenciar a conexão e desconexão de clientes.

A classe asio::ip::icmp é derivada da classe asio::basic_socket<Protocol>, que é uma classe genérica que representa um socket de rede. Ela fornece uma interface para criar e gerenciar sockets de rede usando qualquer protocolo de rede suportado pelo Asio. A classe asio::ip::icmp é uma especialização da classe asio::basic_socket<Protocol> para o protocolo ICMP.

A classe asio::ip::icmp fornece os seguintes métodos e funcionalidades:

  • connect: estabelece uma conexão com um host especificado através de um endpoint ICMP.
  • close: fecha o socket e interrompe qualquer conexão existente.
  • read: lê dados de um socket e armazena os dados em um buffer de saída.
  • write: escreve dados de um buffer em um socket.

Além disso, a classe asio::ip::icmp fornece várias configurações de socket, como opções de buffer de entrada e saída, opções de tempo de espera e opções de recurso. Essas opções podem ser ajustadas usando os métodos set_option e get_option da classe asio::ip::icmp.

Aqui está um exemplo de como a classe asio::ip::icmp pode ser usada para implementar um programa em C++ que envia uma mensagem ICMP para um host especificado e aguarda por uma resposta:

#include <iostream>
#include <chrono>
#include <asio.hpp>


// Constantes para os campos protocol e type
const unsigned char IPPROTO_ICMP = 1;
const unsigned char ICMP_ECHO = 8;
const unsigned char ICMP_ECHOREPLY = 0;
const unsigned char ICMP_DEST_UNREACH = 3;
const unsigned char ICMP_TIME_EXCEEDED = 11;

struct iphdr
{
    unsigned char  ihl:4;
    unsigned char  version:4;
    unsigned char  tos;
    unsigned short tot_len;
    unsigned short id;
    unsigned short frag_off;
    unsigned char  ttl;
    unsigned char  protocol;
    unsigned short check;
    unsigned int   saddr;
    unsigned int   daddr;
};

struct icmphdr
{
    unsigned char  type;
    unsigned char  code;
    unsigned short checksum;
    union un
    {
        struct echo
        {
            unsigned short id;
            unsigned short sequence;
        };
        unsigned int   gateway;
        struct frag
        {
            unsigned short __unused;
            unsigned short mtu;
        };
    };
};

int main()
{
    // Cria um objeto io_context doAsio
    asio::io_context io_context;

    // Cria um socket ICMP
    asio::ip::icmp::socket socket(io_context);

    // Configura um endpoint ICMP para o host
    asio::ip::icmp::endpoint host_endpoint("www.example.com", 0);

    // Conecta o socket ao host
    socket.connect(host_endpoint);

    // Envia um ping para o host
    std::vector<unsigned char> ping(sizeof(icmphdr) + sizeof(iphdr) + 8);
    iphdr* ip_header = reinterpret_cast<iphdr*>(ping.data());
    ip_header->ihl = 5;
    ip_header->version = 4;
    ip_header->tot_len = htons(ping.size());
    ip_header->protocol = IPPROTO_ICMP;
    ip_header->saddr = inet_addr("127.0.0.1");
    ip_header->daddr = inet_addr("www.example.com");
    icmphdr* icmp_header = reinterpret_cast<icmphdr*>(ping.data() + sizeof(iphdr));
    icmp_header->type = ICMP_ECHO;
    icmp_header->code = 0;
    icmp_header->un.echo.id = htons(1234);
    icmp_header->un.echo.sequence = htons(1);
    *reinterpret_cast<unsigned long*>(ping.data() + sizeof(icmphdr) + sizeof(iphdr)) = htonl(time(nullptr));

    // Calcula o checksum do ping
    icmp_header->checksum = 0;
    icmp_header->checksum = asio::ip::icmp::checksum(ping.data(), ping.size());

    // Armazena o tempo de envio do ping
    auto send_time = std::chrono::high_resolution_clock::now();

    // Envia o ping para o host
    asio::write(socket,asio::buffer(ping));

    // Aguarda por uma resposta de ping do host
    std::vector<unsigned char> reply(1024);
    size_t bytes_received = asio::read(socket, asio::buffer(reply));

    // Verifica se o tipo de mensagem recebida é um ICMP_ECHOREPLY
    iphdr* reply_ip_header = reinterpret_cast<iphdr*>(reply.data());
    icmphdr* reply_icmp_header = reinterpret_cast<icmphdr*>(reply.data() + (reply_ip_header->ihl * 4));
    if (reply_icmp_header->type == ICMP_ECHOREPLY)
    {
        // Calcula o tempo de viagem do ping
        auto trip_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - send_time).count();

        // Imprime o resultado do ping
        std::cout << "Recebida resposta de ping do host em " << trip_time << " ms" << std::endl;
    }
    else
    {
        std::cout << "Tipo de mensagem não reconhecido" << std::endl;
    }

    return 0;
}