Reg Issue observed while trying to Ping IPV6 using ICMPV6 protocol via socket layer - CPP

23 Views Asked by At

The sendto() and recvfrom() functions in the C++ code I wrote to ping IPV6 using icmpv6 via socket layer always return a value of 64, regardless of whether the IPV6 address is reachable or not.

Need someone assistance in figuring out what went wrong and how to fix it?

Code logic:


#include <iostream>

#ifdef UNIX

#include <sys/socket.h>
#ifdef PLATFORM_OSX
#include <netinet/ip.h>
#else
#include <netinet/in.h>
#endif
#include <net/if.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>

#define PACKET_SIZE 64


class CPingCommandIPV6
{
  CPingCommandIPV6(const std::string& hostname, int timeout) :
    m_Timeout(timeout),
    m_Hostname(hostname)
  {
    m_Socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    if (m_Socket < 0)
    {
      LOG_ERROR("Ping: failed to create socket IPV6 - %s", strerror(errno));
      return false;
    }
    LOG_INFO("Socket Creation Successful for IPV6 :: %s", m_Hostname.c_str());

    //Set TTL(Time to Live)
    m_Ttl = 64;
    setsockopt(m_Socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &m_Ttl, sizeof(m_Ttl));
   

    memset(&m_To, 0, sizeof(m_To));
    m_To.sin6_family = AF_INET6;
    //m_To.sin6_addr = in6addr_any;
    inet_pton(AF_INET6, m_Hostname.c_str(), &m_To.sin6_addr)  

    // Prepare ICMPv6 echo request packet
    struct icmp6_hdr *pIcmpPacket = (struct icmp6_hdr*)m_RequestPacket;
    //Initialize ICMPV6 header
    pIcmpPacket->icmp6_type = ICMP6_ECHO_REQUEST;
    pIcmpPacket->icmp6_code = 0;
    pIcmpPacket->icmp6_cksum = 0;
    pIcmpPacket->icmp6_seq = htons(0);  /* seq and id must be reflected */
    pIcmpPacket->icmp6_id = htons(getpid());
    memset(m_RequestPacket + sizeof(struct icmp6_hdr), 0, PACKET_SIZE - sizeof(struct icmp6_hdr));
    LOG_INFO("Packet initialization part for IPV6");
    pIcmpPacket->icmp6_cksum = checksum(m_RequestPacket, PACKET_SIZE);

  }
public:
  bool RunIPV6();
private:
  int m_Timeout;
  int m_Socket;
  int m_Ttl;
  std::string m_Hostname;
  struct sockaddr_in6 m_To;
  uint8_t m_RequestPacket[PACKET_SIZE];
  uint8_t m_ReplyPacket[PACKET_SIZE];
};
CPingCommandIPV6::CPingCommandIPV6(const std::string& hostname, int timeout)
  : m(std::make_unique<CPingCommandIPV6::Impl>(hostname, timeout))
{
}

CPingCommandIPV6::~CPingCommandIPV6()
{
  close(m_Socket);
}
bool CPingCommandIPV6::RunIPV6()
{
  LOG_INFO("PingCommand Before sending - IPV6");
  int sent = sendto(m_Socket, m_RequestPacket, PACKET_SIZE, 0, (struct sockaddr*)&m_To, (socklen_t)sizeof(struct sockaddr_in6));

  LOG_INFO("PingCommand After sending - IPV6 :: %d", sent);
  if (sent <= 0)
  {
    LOG_INFO("PingCommand Request not sent IPV6 :: %d", sent);
    return false;
  }
  else
  {
    LOG_INFO("Ping command request sent properly :: %d", sent);
  }

  fd_set rfds;
  FD_ZERO(&rfds);
  FD_SET(m_Socket, &rfds);

  struct timeval tv;
  tv.tv_sec = m_Timeout / 1000;
  tv.tv_usec = (m_Timeout % 1000) * 1000;

  bool cont = true;
  while (cont)
  {
    LOG_INFO("Listen for replies1 - IPV6");
    int retval = select(m_Socket + 1, &rfds, NULL, NULL, &tv);
    if (retval == -1)
    {
      LOG_INFO("Listen for replies2 - IPV6");
      return false;
    }
    else if (retval == 0)
    {
      // timeout
      LOG_INFO("Listen for replies3 - IPV6");
      return false;
    }
    else
    {
      LOG_INFO("Listen for replies4 - IPV6");
      //Receive ICMPV6 response
      struct sockaddr_in6 from;
      socklen_t fromlen = sizeof(from);
      LOG_INFO("PingCommand Before Receive from -IPV6");
      int ret = recvfrom(m_Socket, (char*)m_ReplyPacket, PACKET_SIZE, 0, (sockaddr*)&from, &fromlen);

      LOG_INFO("PingCommand After Receiving from - IPV6 :: %d", ret);
      if (ret <= 0)
      {
        LOG_INFO("PingCommand not received from - IPV6 :: %d", ret);
        return false;
      }
      else
      {
        //LOG_INFO("Received ICMPV6 response from:: %s",inet_ntop(AF_INET6, &from.sin6_addr,(char*)m_ReplyPacket, sizeof(m_ReplyPacket)));
        LOG_INFO("RunIPV6() returns true successfully- IPV6 :: %d", ret);
        return true;
      }
    }
  }
}

int main()
{
      static uint32_t kTimeout = 1000;
      std::string m_ipv6Address = "1050:0000:0000:0000:0005:0600:300c:326b";
      CPingCommandIPV6 PingIPV6(m_IpAddress, kTimeout);

      //To check physical connection
      if (PingIPV6.RunIPV6())
      {
        LOG_DEBUG("IPV6 Ping successful");
      }
      else
      {
        LOG_DEBUG("Time out  - IPV6");
      }
      return 0;
}
#endif

Expectation:

  • Ping IPv6 address if the address is reachable and return true for RunIPV6() else return false.
  • But In my case, it always return true regardless of IPV6 Address is reachable or not. Because sendto() api always returns 64 in both the successful and not successful cases.

I expect the code should return <=0 if ipv6 address are not reachable.

0

There are 0 best solutions below