Z
Z
zergon3212017-08-27 14:47:33
Computer networks
zergon321, 2017-08-27 14:47:33

Why doesn't self-written tracert work?

I made my own implementation of traceroute . No router is responding to the ping request. The normal tracert built into Windows works fine. ping , which I took part of the code for tracert , also works fine. Removed setsockopt() - still no response, timeout was exceeded everywhere. The algorithm used is as follows: for each TTL , 3 ICMP echo request packets are sent in turn , for each a response from the router is expected. The program terminates when the TTL exceeds the maximum hop count or when an ICMP is received.-message like echo reply . I scanned all this with Wireshark - echo requests are sent, time exceeded responses come, but the program considers that they do not exist at all, select () does not wait (although it should), ICMP responses are simply not accepted. What needs to be done to make everything work?

main() code
#include "winsock_error.h"
#include "io_ext.h"
#include <cstdio>

#define SOCK_NUM 3

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable : 4996)

int main()
{
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);

  WSADATA filler;

  if (WSAStartup(WSA_VERSION, &filler))
  {
    output_error("Couldn't initialize WSA");
    return EXIT_FAILURE;
  }

  char host_name[MAXGETHOSTSTRUCT];

  enter_message("Please enter a host name: ", host_name);
  std::cout << std::endl;

  LPHOSTENT remote_host_info = gethostbyname(host_name);

  if (remote_host_info == NULL)
  {
    output_error("Couldn't get a host info");
    finalize();

    return EXIT_FAILURE;
  }

  if (remote_host_info->h_addrtype == AF_INET6)
  {
    output_error("Sorry, but R-Scan can't perform scanning of ipv6-hosts");
    finalize();

    return EXIT_SUCCESS;
  }

  //ALIASES SHOWING
  if (remote_host_info->h_aliases[0])
  {
    std::cout << "Server name aliases: " << std::endl;

    for (int i = 0; remote_host_info->h_aliases[i]; i++)
      std::cout << remote_host_info->h_aliases[i] << std::endl;

    std::cout << std::endl;
  }
  else
    std::cout << "Host has no aliases" << std::endl << std::endl;

  in_addr tmp;

  //ADDRESSES SHOWING
  if (remote_host_info->h_addr_list[1])
  {
    std::cout << "Server addresses: " << std::endl;

    for (int i = 0; remote_host_info->h_addr_list[i]; i++)
    {
      tmp.s_addr = *(LPWORD)remote_host_info->h_addr_list[i];
      std::cout << inet_ntoa(tmp) << std::endl;
    }

    std::cout << std::endl;
  }
  else
  {
    std::cout << "Server address: ";
    tmp.s_addr = *(u_long*)remote_host_info->h_addr;
    std::cout << inet_ntoa(tmp) << std::endl << std::endl;
  }

  WORD temp;
  BYTE max_hops_num;

  //MAX HOPS NUM INPUT
  while (true)
  {
    std::cout << "Please enter max number of hops: ";
    (std::cin >> temp).get();

    if (!std::cin || temp > TTL_MAX_VAL || temp == 0)
    {
      clear_istream(std::cin);
      std::cerr << "You entered wrong value; try again" << std::endl << std::endl;
    }
    else
      break;
  }

  __asm //firstly value is assigned to 16 bit temporary variable, then left octet of temporary variable is assigned to max_hops_num variable
  {
    mov ax, temp
    mov max_hops_num, al
  }

  fd_set read;
  SOCKET sock = ICMP_SOCKET;
  sockaddr_in server_data;
  ECHO_REQUEST echo_req;
  ECHO_REPLY echo_rep;
  timeval wait_time = { 2, 0 };

  //CONNECTION DATA FILLING
  server_data.sin_family = AF_INET;
  server_data.sin_port = 0;
  tmp.s_addr = *(LPWORD)&remote_host_info->h_addr;
  inet_pton(AF_INET, (PCSTR)inet_ntoa(tmp), &server_data.sin_addr);

  //ICMP HDR AND ECHO_REQUEST STRUCT FILLING
  echo_req.icmp_hdr.type = ICMP_ECHO_REQ;
  echo_req.icmp_hdr.code = 0;
  echo_req.icmp_hdr.id = 1;
  echo_req.icmp_hdr.seq = 0;
  echo_req.icmp_hdr.checksum = 0;
  echo_req.dw_time = GetTickCount();
  memset(echo_req.data, ECHO_FILLER, PACK_FRAME_SIZE);
  echo_req.icmp_hdr.checksum = checksum((LPWORD)&echo_req, sizeof(echo_req));

  //TRACERT LOOP
  for (BYTE TTL = 1; TTL <= max_hops_num; TTL++)
  {
    tmp.s_addr = 0;
    printf("%3d\t", TTL);

    //set TTL
    if (setsockopt(sock, IPPROTO_IP, IP_TTL, (PCSTR)&TTL, sizeof(TTL)) == SOCKET_ERROR)
    {
      error_to_close_socket("Couldn't set IP header TTL", sock);
      finalize();

      return EXIT_FAILURE;
    }

    //send 3 ICMP echo requests
    RANGE(0, SOCK_NUM)
    {
      echo_req.dw_time = GetTickCount();
      echo_req.icmp_hdr.checksum = checksum((LPWORD)&echo_req, sizeof(echo_req));

      if (sendto(sock, (LPSTR)&echo_req, sizeof(echo_req), 0, (LPSOCKADDR)&server_data, sizeof(server_data)) == SOCKET_ERROR)
      {
        error_to_close_socket("Couldn't perform a ping", sock);
        finalize();

        return EXIT_FAILURE;
      }

      FD_ZERO(&read);
      FD_SET(sock, &read);

      int ret = select(0, &read, NULL, NULL, &wait_time);

      if (ret == SOCKET_ERROR)
      {
        error_to_close_socket("Couldn't perform data awaiting", sock);
        finalize();

        return EXIT_FAILURE;
      }
      else if (ret == 0)
      {
        std::cout << " * \t";
      }
      else
      {
        if (recvfrom(sock, (LPSTR)&echo_rep, sizeof(ECHO_REPLY), 0, NULL, NULL) == SOCKET_ERROR)
        {
          error_to_close_socket("Couldn't receive ICMP", sock);
          finalize();

          return EXIT_FAILURE;
        }

        printf("%4d ms\t", GetTickCount() - echo_rep.echo_request.dw_time);
        tmp = echo_rep.ip_hdr.src_addr;
      }
    }

    if (tmp.s_addr == 0)
    {
      std::cout << "Waiting time exceeded" << std::endl;
      continue;
    }

    remote_host_info = gethostbyaddr((PCSTR)&echo_rep.ip_hdr.src_addr, AF_INET_ADDR_LEN, AF_INET);

    if (remote_host_info == NULL)
      std::cout << inet_ntoa(echo_rep.ip_hdr.src_addr) << std::endl;
    else
      printf("%s [%s]", remote_host_info->h_name, inet_ntoa(echo_rep.ip_hdr.src_addr));

    if (echo_rep.echo_request.icmp_hdr.type == 0 && echo_rep.echo_request.icmp_hdr.code == 0)
      break;
  }
}


header file
#pragma once
#ifndef WINSOCK_ERROR
#define WINSOCK_ERROR

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <ctime>
#include <WS2tcpip.h>

#define ECHO_PORT 32768
#define WSA_VERSION 0x0202
#define LOCALHOST "127.0.0.1"
#define BUFF_SIZE 8192
#define BACKLOG 4
#define WAIT_TIME 1
#define INPUT_BUFF 16
#define PACK_FRAME_SIZE 64
#define REPLY_DATA_SIZE 0x100
#define TTL_MAX_VAL 0xFF
#define ICMP_ECHO_REQ 8
#define ECHO_FILLER 87
#define EVERLAST_HOPS_PARAM 0
#define AF_INET_ADDR_LEN 4
#define TCP_SOCKET socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)
#define UDP_SOCKET socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)
#define ICMP_SOCKET socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)

namespace con_mode
{
  enum mode
  {
    write, //socket condition for sending data
    read, //socket condition for receiving data
    input, //socket condition for entering data by user
    timeout //socket condition for inactivity
  };
}

typedef struct ICMP_hdr //ICMP header representation
{
  BYTE type;
  BYTE code;
  WORD checksum;
  WORD id;
  WORD seq;
} ICMP_HDR;

typedef struct echo_request //packet that will be sent through the network
{
  ICMP_HDR icmp_hdr;
  DWORD dw_time;
  char data[PACK_FRAME_SIZE];
} ECHO_REQUEST;

typedef struct ip_hdr
{
  BYTE ver_ihl; //4 bit for version, 4 bit for internet header length (in DWORDs)
  BYTE dscp_ecn; //DiffServ: 6 bit for dscp (packet priority or ToS) and 2 bit ECN (congestion flag); if congestion exists, transmission rate reduces 
  WORD tot_len; //length of header + data, 16 bit field
  WORD id; //for packet fragments identifying (if a packet was fragmented)
  WORD flag_off; //flags of fragmentation and fragment offset; 1st bit - reserved; 2nd bit - if set, packet won't be fragmented if it need and will be dropped;
  //3rd bit - set for all fragmented packets; fragment offset - 13 bit field, defines a fragment offset relative to the beginnig of original IP datagram; measured in 64 bit blocks
  BYTE TTL; //time-to-live, 8 bit field; measured determined bu the number of gateways and hosts packet can traverse
  BYTE protocol; //8 bit field; protocol list: https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
  WORD checksum; //16 bit field; if it hasn't been computed yet, it must be equal to 0
  in_addr src_addr; //32 bit sender IP address
  in_addr dst_addr; //32 bit receiver IP address
} IP_HDR;

typedef struct echo_reply //ICMP echo response from server
{
  IP_HDR ip_hdr;
  ECHO_REQUEST echo_request;
  char c_filler[REPLY_DATA_SIZE];
} ECHO_REPLY;

inline USHORT checksum(USHORT *buffer, int size)
{
  unsigned long cksum = 0;

  while (size > 1)
  {
    cksum += *buffer++;
    size -= sizeof(USHORT);
  }
  if (size)
  {
    cksum += *(UCHAR*)buffer;
  }
  cksum = (cksum >> 16) + (cksum & 0xffff);
  cksum += (cksum >> 16);
  return (USHORT)(~cksum);
}

inline void output_error(const char* message)
{
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
  std::cerr << message << std::endl;
  std::cerr << "Error code: " << WSAGetLastError() << std::endl;
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
}

inline void finalize()
{
  WSACleanup();
  system("pause");
}

inline void close_socket(SOCKET sock)
{
  if (closesocket(sock) == SOCKET_ERROR)
  {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
    std::cerr << "Couldn't close socket: error " << WSAGetLastError() << std::endl;
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
  }
}

inline void error_to_close_socket(const char* message, SOCKET sock)
{
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);

  output_error(message);
  close_socket(sock);

  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
}

#endif


Screenshot of the sniffer:26fc208b251c4ab38b41998912a0e9f6.png

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
res2001, 2017-08-27
@res2001

A lot of code, did not master.
Take any sniffer (NetworkMonitor, WireShark) and watch the traffic with it, what leaves you, what comes to you.
And to begin with, train on the nearest nodes that are in your network.
There will be a result from a sniffer, then it is possible to think something further.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question