Advertisement
Guest User

Untitled

a guest
Nov 12th, 2019
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.01 KB | None | 0 0
  1. #include <iostream>
  2. #include <thread>
  3. #include <cstring>
  4. #include <unistd.h>
  5. #include <linux/icmp.h>
  6. #include <linux/icmpv6.h>
  7. #include <dnet.h>
  8.  
  9. struct icmp_packet {
  10.     icmp6hdr header{};
  11.     char msg[56]{};
  12.  
  13.     explicit icmp_packet(const char *msg, bool is_ipv6) {
  14.         header.type = is_ipv6 ? ICMPV6_ECHO_REQUEST : ICMP_ECHO;
  15.         header.code = 0;
  16.         header.un.echo.id = getpid();
  17.         header.un.echo.sequence = 0;
  18.         strncpy(this->msg, msg, 55);
  19.         checksum();
  20.     }
  21.  
  22.     uint16_t checksum() {
  23.         this->header.checksum = 0;
  24.         int len = sizeof(*this);
  25.         auto *current = reinterpret_cast<const uint16_t *>(this);
  26.         uint32_t sum = 0;
  27.         while (len > 1) {
  28.             len -= 2;
  29.             sum += *current++;
  30.         }
  31.         if (len)
  32.             sum += *reinterpret_cast<const uint8_t *>(current);
  33.         sum = (sum >> 16u) + (sum & 0xFFFFu);
  34.         sum += sum >> 16u;
  35.         return this->header.checksum = ~sum;
  36.     }
  37. };
  38.  
  39. char *dns_lookup(const char *hostname, sockaddr_storage &addr, bool &is_ipv6) {
  40.     static char ip[INET6_ADDRSTRLEN];
  41.     static addrinfo hint{}, *res = nullptr;
  42.     hint.ai_family = PF_UNSPEC;
  43.     hint.ai_flags = AI_ALL;
  44.  
  45.     if (getaddrinfo(hostname, nullptr, &hint, &res)) {
  46.         std::cerr << "Invalid address" << std::endl;
  47.         return nullptr;
  48.     }
  49.     is_ipv6 = res->ai_family == AF_INET6;
  50.     memcpy(&addr, res->ai_addr, sizeof(addr));
  51.     if (is_ipv6)
  52.         inet_ntop(res->ai_family, &(reinterpret_cast<sockaddr_in6 *>(res->ai_addr)->sin6_addr), ip, res->ai_addrlen);
  53.     else
  54.         inet_ntop(res->ai_family, &(reinterpret_cast<sockaddr_in *>(res->ai_addr)->sin_addr), ip, res->ai_addrlen);
  55.     return ip;
  56. }
  57.  
  58. void send_request(int sock_fd, const sockaddr_storage &addr, bool is_ipv6 = false) {
  59.     icmp_packet packet("echo requests", is_ipv6);
  60.     icmp_packet buffer("echo reply", is_ipv6);
  61.     sockaddr_storage r_addr{};
  62.     socklen_t r_len = sizeof(r_addr);
  63.     int cnt = 4;
  64.     while (cnt--) {
  65.         if (sendto(sock_fd, &packet, sizeof(packet), 0,
  66.                    reinterpret_cast<const sockaddr *>(&addr), sizeof(addr)) < 1) {
  67.             std::cerr << "Failed to send packet" << std::endl;
  68.             continue;
  69.         }
  70.  
  71.         auto start = std::chrono::high_resolution_clock::now();
  72.         //recvfrom(sock_fd, &buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr*>(&r_addr), &r_len);
  73.         recvfrom(sock_fd, &buffer, sizeof(buffer), 0, nullptr, nullptr);
  74.  
  75.         if (buffer.header.type != 69 + 60 * is_ipv6 || buffer.header.code) {
  76.             std::cout << "Broken packet with type " << (int) buffer.header.type
  77.                       << " and code " << (int) buffer.header.code << std::endl;
  78.             std::cout << buffer.msg << std::endl;
  79.             continue;
  80.         }
  81.  
  82.         auto end = std::chrono::high_resolution_clock::now();
  83.         std::chrono::duration<double, std::milli> rtt = end - start;
  84.         std::cout << "Received reply: seq=" << packet.header.un.echo.sequence
  85.                   << " rrt=" << rtt.count() << "ms" << std::endl;
  86.         ++packet.header.un.echo.sequence;
  87.         packet.checksum();
  88.         using namespace std::chrono_literals;
  89.         std::this_thread::sleep_for(500ms);
  90.     }
  91.  
  92. }
  93.  
  94. int main(int argc, char **argv) {
  95.     if (argc < 2) {
  96.         std::cout << "Usage: " << argv[0] << " " << "(hostname|ip address)" << std::endl;
  97.         return 1;
  98.     }
  99.     bool is_ipv6 = true;
  100.     sockaddr_storage addr{};
  101.     char *ip = dns_lookup(argv[1], addr, is_ipv6);
  102.     std::cout << "PING " << argv[1] << " (" << ip << ")" << std::endl;
  103.     int sock_fd = socket(is_ipv6 ? AF_INET6 : AF_INET, SOCK_RAW, is_ipv6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
  104.     if (sock_fd < 0) {
  105.         std::cerr << "Cannot open socket fd\n" << "Consider running with sudo" << std::endl;
  106.         return sock_fd;
  107.     }
  108.     int ttl = 64;
  109.     setsockopt(sock_fd, is_ipv6 ? SOL_IPV6 : SOL_IP, IP_TTL, &ttl, sizeof(ttl));
  110.     send_request(sock_fd, addr, is_ipv6);
  111.     return 0;
  112. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement