< RAW Socket, ICMP & Ping | RAW Socket Main | Traceroute Program Example >


 

 

Raw Sockets 11 Part 2

 

 

What do we have in this chapter 11 part 2?

  1. IPv4 and IPv6 Ping Program Example

 

IPv4 and IPv6 Ping Program Example

 

The following program example illustrates how to create a socket capable of sending and receiving ICMP packets, as well as how to use the IP_OPTIONS socket option to implement the record route option (supported for IPv4 only).

 

IPv4 and IPv6 Ping Program Examplel: Create a new empty Win32 console mode application for IPv4 and IPv6 Ping Program Example.

 

Add the following source code.

 

// Sample: IPv4 and IPv6 Ping Sample

//

// Files:

//    iphdrv2.h       - IPv4 and IPv6 packet header definitions

//    ipv4ipv6pingexamplesrc.cpp      - this file

//    resolve.cpp   - Common name resolution routine

//    resolve.h     - Header file for common name resolution routines

//

// Description:

//    This sample illustrates how to use raw sockets to send ICMP

//    echo requests and receive their response. This sample performs

//    both IPv4 and IPv6 ICMP echo requests. When using raw sockets,

//    the protocol value supplied to the socket API is used as the

//    protocol field (or next header field) of the IP packet. Then

//    as a part of the data submitted to sendto, we include both

//    the ICMP request and data.

//

//    For IPv4 the IP record route option is supported via the

//    IP_OPTIONS socket option.

//

// Command Line Options/Parameters:

//     ipv4ipv6pingexample [-a 4|6] [-i ttl] [-l datasize] [-r] [host]

//

//     -a       Address family (IPv4 or IPv6)

//     -i ttl   TTL value to set on socket

//     -l size  Amount of data to send as part of the ICMP request

//     -r       Use IPv4 record route

//     host     Hostname or literal address

//

#ifndef WIN32_LEAN_AND_MEAN

#define WIN32_LEAN_AND_MEAN

#endif

 

// Link to ws2_32.lib

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <stdlib.h>

#include "resolve.h"

#include "iphdrv2.h"

 

#define DEFAULT_DATA_SIZE      32               // default data size

#define DEFAULT_SEND_COUNT     4            // number of ICMP requests to send

#define DEFAULT_RECV_TIMEOUT   6000    // six second

#define DEFAULT_TTL            128

 

int   gAddressFamily=AF_UNSPEC,         // Address family to use

      gProtocol=IPPROTO_ICMP,                // Protocol value

      gTtl=DEFAULT_TTL;                             // Default TTL value

int   gDataSize=DEFAULT_DATA_SIZE;      // Amount of data to send

BOOL  bRecordRoute=FALSE;                   // Use IPv4 record route?

char *gDestination=NULL;                            // Destination

 

// Function: usage

// Description: Print usage information.

int usage(char *progname)

{

    printf("Usage: %s -r <host> [data size]\n", progname);

    printf("       -a 4|6       Address family\n");

    printf("       -i ttl       Time to live\n");

    printf("       -l bytes     Amount of data to send\n");

    printf("       -r           Record route (IPv4 only)\n");

    printf("        host        Remote machine to ping\n");

    printf("Example: ipv4ipv6pingexample -a 4 -l 64 -r www.google.com\n");

    printf("\n");

    return 0;

}

 

// Function: InitIcmpHeader

// Description: Helper function to fill in various stuff in our ICMP request.

void InitIcmpHeader(char *buf, int datasize)

{

    ICMP_HDR   *icmp_hdr=NULL;

    char       *datapart=NULL;

 

    icmp_hdr = (ICMP_HDR *)buf;

    icmp_hdr->icmp_type     = ICMPV4_ECHO_REQUEST_TYPE;        // request an ICMP echo

    icmp_hdr->icmp_code     = ICMPV4_ECHO_REQUEST_CODE;

    icmp_hdr->icmp_id       = (USHORT)GetCurrentProcessId();

    icmp_hdr->icmp_checksum = 0;

    icmp_hdr->icmp_sequence = 0;

    icmp_hdr->icmp_timestamp= GetTickCount();

 

    datapart = buf + sizeof(ICMP_HDR);

 

    // Place some junk in the buffer.

    memset(datapart, 'E', datasize);

}

 

// Function: InitIcmp6Header

// Description: Initialize the ICMP6 header as well as the echo request header.

int InitIcmp6Header(char *buf, int datasize)

{

    ICMPV6_HDR          *icmp6_hdr=NULL;

    ICMPV6_ECHO_REQUEST *icmp6_req=NULL;

    char                *datapart=NULL;

 

    // Initialize the ICMP6 header fields

    icmp6_hdr = (ICMPV6_HDR *)buf;

    icmp6_hdr->icmp6_type     = ICMPV6_ECHO_REQUEST_TYPE;

    icmp6_hdr->icmp6_code     = ICMPV6_ECHO_REQUEST_CODE;

    icmp6_hdr->icmp6_checksum = 0;

    // Initialize the echo request fields

    icmp6_req = (ICMPV6_ECHO_REQUEST *)(buf + sizeof(ICMPV6_HDR));

    icmp6_req->icmp6_echo_id       = (USHORT)GetCurrentProcessId();

    icmp6_req->icmp6_echo_sequence = 0;

 

    datapart = (char *)buf + sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);

    memset(datapart, '$', datasize);

    return (sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST));

}

 

// Function: checksum

// Description: This function calculates the 16-bit one's complement sum of the supplied buffer (ICMP) header.

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);

}

 

// Function: ValidateArgs

// Description: Parse the command line arguments.

void ValidateArgs(int argc, char **argv)

{

    int    i;

 

    for(i=1; i < argc ;i++)

    {

        if ((argv[i][0] == '-') || (argv[i][0] == '/'))

        {

            switch (tolower(argv[i][1]))

            {

                case 'a':        // address family

                    if (i+1 >= argc)

                        usage(argv[0]);

                    if (argv[i+1][0] == '4')

                        gAddressFamily = AF_INET;

                    else if (argv[i+1][0] == '6')

                        gAddressFamily = AF_INET6;

                    else

                        usage(argv[0]);

                    i++;

                    break;

                case 'i':        // Set TTL value

                    if (i+1 >= argc)

                        usage(argv[0]);

                    gTtl = atoi(argv[++i]);

                    break;

                case 'l':        // buffer size tos end

                    if (i+1 >= argc)

                        usage(argv[0]);

                    gDataSize = atoi(argv[++i]);

                    break;

                case 'r':        // record route option

                    bRecordRoute = TRUE;

                    break;

                default:

                    usage(argv[0]);

                    break;

            }

        }

        else

        {

            gDestination = argv[i];

        }

    }

    return;

}

 

// Function: SetIcmpSequence

// Description: This routine sets the sequence number of the ICMP request packet.

void SetIcmpSequence(char *buf)

{

    ULONG    sequence=0;

 

    sequence = GetTickCount();

    if (gAddressFamily == AF_INET)

    {

        ICMP_HDR    *icmpv4=NULL;

 

        icmpv4 = (ICMP_HDR *)buf;

        icmpv4->icmp_sequence = (USHORT)sequence;

    }

    else if (gAddressFamily == AF_INET6)

    {

        ICMPV6_HDR          *icmpv6=NULL;

        ICMPV6_ECHO_REQUEST *req6=NULL;

 

        icmpv6 = (ICMPV6_HDR *)buf;

        req6   = (ICMPV6_ECHO_REQUEST *)(buf + sizeof(ICMPV6_HDR));

 

        req6->icmp6_echo_sequence = (USHORT)sequence;

    }

}

 

// Function: ComputeIcmp6PseudoHeaderChecksum

// Description:

//    This routine computes the ICMP6 checksum which includes the pseudo

//    header of the IPv6 header (see RFC2460 and RFC2463). The one difficulty

//    here is we have to know the source and destination IPv6 addresses which

//    will be contained in the IPv6 header in order to compute the checksum.

//    To do this we call the SIO_ROUTING_INTERFACE_QUERY ioctl to find which

//    local interface for the outgoing packet.

USHORT ComputeIcmp6PseudoHeaderChecksum(SOCKET s, char *icmppacket, int icmplen, struct addrinfo *dest)

{

    SOCKADDR_STORAGE localif;

    DWORD            bytes;

    char             tmp[65535], *ptr=NULL, proto=0, zero=0;

    int              rc, total, length, i;

 

    // Find out which local interface for the destination

    rc = WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, dest->ai_addr,dest->ai_addrlen,

            (SOCKADDR *)&localif, sizeof(localif), &bytes, NULL, NULL);

    if (rc == SOCKET_ERROR)

    {

        fprintf(stderr, "WSAIoctl() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("WSAIoctl() is OK!\n");

    // We use a temporary buffer to calculate the pseudo header.

    ptr = tmp;

    total = 0;

 

    // Copy source address

    memcpy(ptr, &((SOCKADDR_IN6 *)&localif)->sin6_addr, sizeof(struct in6_addr));

    ptr   += sizeof(struct in6_addr);

    total += sizeof(struct in6_addr);

    // Copy destination address

    memcpy(ptr, &((SOCKADDR_IN6 *)dest->ai_addr)->sin6_addr, sizeof(struct in6_addr));

    ptr   += sizeof(struct in6_addr);

    total += sizeof(struct in6_addr);

    // Copy ICMP packet length

    length = htonl(icmplen);

 

    memcpy(ptr, &length, sizeof(length));

    ptr   += sizeof(length);

    total += sizeof(length);

    // Zero the 3 bytes

    memset(ptr, 0, 3);

    ptr   += 3;

    total += 3;

    // Copy next hop header

    proto = IPPROTO_ICMP6;

 

    memcpy(ptr, &proto, sizeof(proto));

    ptr   += sizeof(proto);

    total += sizeof(proto);

    // Copy the ICMP header and payload

    memcpy(ptr, icmppacket, icmplen);

    ptr   += icmplen;

    total += icmplen;

 

    for(i=0; i < icmplen%2 ;i++)

    {

        *ptr = 0;

        ptr++;

        total++;

    }

    return checksum((USHORT *)tmp, total);

}

 

// Function: ComputeIcmpChecksum

// Description:

//    This routine computes the checksum for the ICMP request. For IPv4 its

//    easy, just compute the checksum for the ICMP packet and data. For IPv6,

//    its more complicated. The pseudo checksum has to be computed for IPv6

//    which includes the ICMP6 packet and data plus portions of the IPv6

//    header which is difficult since we aren't building our own IPv6 header

void ComputeIcmpChecksum(SOCKET s, char *buf, int packetlen, struct addrinfo *dest)

{

    if (gAddressFamily == AF_INET)

    {

        ICMP_HDR    *icmpv4=NULL;

 

        icmpv4 = (ICMP_HDR *)buf;

        icmpv4->icmp_checksum = 0;

        icmpv4->icmp_checksum = checksum((USHORT *)buf, packetlen);

    }

    else if (gAddressFamily == AF_INET6)

    {

        ICMPV6_HDR  *icmpv6=NULL;

 

        icmpv6 = (ICMPV6_HDR *)buf;

        icmpv6->icmp6_checksum = 0;

        icmpv6->icmp6_checksum = ComputeIcmp6PseudoHeaderChecksum(s, buf, packetlen, dest);

    }

}

 

// Function: PostRecvfrom

// Description: This routine posts an overlapped WSARecvFrom on the raw socket.

int PostRecvfrom(SOCKET s, char *buf, int buflen, SOCKADDR *from, int *fromlen, WSAOVERLAPPED *ol)

{

    WSABUF  wbuf;

    DWORD   flags, bytes;

    int     rc;

 

    wbuf.buf = buf;

    wbuf.len = buflen;

 

    flags = 0;

 

    rc = WSARecvFrom(s, &wbuf, 1, &bytes, &flags, from, fromlen, ol, NULL);

    if (rc == SOCKET_ERROR)

    {

        if (WSAGetLastError() != WSA_IO_PENDING)

        {

            fprintf(stderr, "WSARecvFrom() failed with error code %d\n", WSAGetLastError());

            return SOCKET_ERROR;

        }

    }

    return NO_ERROR;

}

 

// Function: PrintPayload

// Description:

//    This routine is for IPv4 only. It determines if there are any IP options

//    present (by seeing if the IP header length is greater than 20 bytes) and

//    if so it prints the IP record route options.

void PrintPayload(char *buf, int bytes)

{

    int     hdrlen=0, routes=0, i;

 

    if (gAddressFamily == AF_INET)

    {

        SOCKADDR_IN      hop;

        IPV4_OPTION_HDR *v4opt=NULL;

        IPV4_HDR        *v4hdr=NULL;

 

        hop.sin_family = (USHORT)gAddressFamily;

        hop.sin_port   = 0;

 

        v4hdr = (IPV4_HDR *)buf;

        hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;

        // If the header length is greater than the size of the basic IPv4

        //    header then there are options present. Find them and print them.

        if (hdrlen > sizeof(IPV4_HDR))

        {

            v4opt = (IPV4_OPTION_HDR *)(buf + sizeof(IPV4_HDR));

            routes = (v4opt->opt_ptr / sizeof(ULONG)) - 1;

            for(i=0; i < routes ;i++)

            {

                hop.sin_addr.s_addr = v4opt->opt_addr[i];

                // Print the route

                if (i == 0)

                    printf("    Route: ");

                else

                    printf("           ");

                PrintAddress((SOCKADDR *)&hop, sizeof(hop));

 

                if (i < routes-1)

                    printf(" ->\n");

                else

                    printf("\n");

            }

        }

    }

    return;

}

 

// Function: SetTtl

// Description: Sets the TTL on the socket.

int SetTtl(SOCKET s, int ttl)

{

    int     optlevel, option, rc;

 

    rc = NO_ERROR;

    if (gAddressFamily == AF_INET)

    {

        optlevel = IPPROTO_IP;

        option   = IP_TTL;

    }

    else if (gAddressFamily == AF_INET6)

    {

        optlevel = IPPROTO_IPV6;

        option   = IPV6_UNICAST_HOPS;

    }

    else

    {

        rc = SOCKET_ERROR;

    }

    if (rc == NO_ERROR)

    {

        rc = setsockopt(s, optlevel, option, (char *)&ttl, sizeof(ttl));

    }

    if (rc == SOCKET_ERROR)

    {

        fprintf(stderr, "SetTtl: setsockopt() failed: %d\n", WSAGetLastError());

    }

    return rc;

}

 

 

 

 

// Function: main

// Description:

//    Setup the ICMP raw socket and create the ICMP header. Add

//    the appropriate IP option header and start sending ICMP

//    echo requests to the endpoint. For each send and receive we

//    set a timeout value so that we don't wait forever for a

//    response in case the endpoint is not responding. When we receive a packet decode it.

int main(int argc, char **argv)

{

    WSADATA            wsd;

    WSAOVERLAPPED      recvol;

    SOCKET             s=INVALID_SOCKET;

    char              *icmpbuf=NULL, recvbuf[0xFFFF];

    struct addrinfo   *dest=NULL, *local=NULL;

    IPV4_OPTION_HDR    ipopt;

    SOCKADDR_STORAGE   from;

    DWORD              bytes, flags;

    int                packetlen=0, recvbuflen=0xFFFF, fromlen, time=0, rc, i;

 

    if(argc < 2)

    {

        usage(argv[0]);

        exit(1);

    }

 

    // Load Winsock

    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

    {

        printf("WSAStartup() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("WSAStartup() should be fine!\n");

 

    // Parse the command line

    ValidateArgs(argc, argv);

    // Resolve the destination address

    dest = ResolveAddress(gDestination, "0", gAddressFamily, 0, 0);

    if (dest == NULL)

    {

        printf("Bad name %s\n", gDestination);

        return -1;

    }

    else

        printf("ResolveAddress() is pretty damn OK!\n");

 

    gAddressFamily = dest->ai_family;

 

    if (gAddressFamily == AF_INET)

        gProtocol = IPPROTO_ICMP;

    else if (gAddressFamily == AF_INET6)

        gProtocol = IPPROTO_ICMP6;

    // Get the bind address

    local = ResolveAddress(NULL, "0", gAddressFamily, 0, 0);

    if (local == NULL)

    {

        printf("Unable to obtain the bind address!\n");

        return -1;

    }

    else

        printf("ResolveAddress() is pretty damn OK!\n");

 

    // Create the raw socket

    s = socket(gAddressFamily, SOCK_RAW, gProtocol);

    if (s == INVALID_SOCKET)

    {

        printf("socket() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("socket() is OK!\n");

 

    SetTtl(s, gTtl);

 

    // Figure out the size of the ICMP header and payload

    if (gAddressFamily == AF_INET)

        packetlen += sizeof(ICMP_HDR);

    else if (gAddressFamily == AF_INET6)

        packetlen += sizeof(ICMPV6_HDR) + sizeof(ICMPV6_ECHO_REQUEST);

 

    // Add in the data size

    packetlen += gDataSize;

    // Allocate the buffer that will contain the ICMP request

    icmpbuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen);

    if (icmpbuf == NULL)

    {

        fprintf(stderr, "HeapAlloc() for ICMP buffer failed with error code %d\n", GetLastError());

        return -1;

    }

    else

        printf("HeapAlloc() for ICMP buffer is OK!\n");

 

    // Initialize the ICMP headers

    if (gAddressFamily == AF_INET)

    {

        if (bRecordRoute)

        {

            // Setup the IP option header to go out on every ICMP packet

            ZeroMemory(&ipopt, sizeof(ipopt));

            ipopt.opt_code = IP_RECORD_ROUTE; // record route option

            ipopt.opt_ptr  = 4;                 // point to the first addr offset

            ipopt.opt_len  = 39;              // length of option header

 

            rc = setsockopt(s, IPPROTO_IP, IP_OPTIONS, (char *)&ipopt, sizeof(ipopt));

            if (rc == SOCKET_ERROR)

            {

                fprintf(stderr, "setsockopt(IP_OPTIONS) failed with error code %d\n", WSAGetLastError());

                return -1;

            }

            else

                printf("setsockopt(IP_OPTIONS) is OK!\n");

        }

        InitIcmpHeader(icmpbuf, gDataSize);

    }

    else if (gAddressFamily == AF_INET6)

    {

        InitIcmp6Header(icmpbuf, gDataSize);

    }

 

    // Bind the socket -- need to do this since we post a receive first

    rc = bind(s, local->ai_addr, local->ai_addrlen);

    if (rc == SOCKET_ERROR)

    {

        fprintf(stderr, "bind() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("bind() looks fine!\n");

 

    // Setup the receive operation

    memset(&recvol, 0, sizeof(recvol));

    recvol.hEvent = WSACreateEvent();

    // Post the first overlapped receive

    fromlen = sizeof(from);

    PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);

 

    printf("\nPinging --> ");

    PrintAddress(dest->ai_addr, dest->ai_addrlen);

    printf(" with %d bytes of data\n\n", gDataSize);

    // Start sending the ICMP requests

    for(i=0; i < DEFAULT_SEND_COUNT ;i++)

    {

        // Set the sequence number and compute the checksum

        SetIcmpSequence(icmpbuf);

        ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);

 

        time = GetTickCount();

        rc = sendto(s, icmpbuf, packetlen, 0, dest->ai_addr, dest->ai_addrlen);

        if (rc == SOCKET_ERROR)

        {

            fprintf(stderr, "sendto() failed with error code %d\n", WSAGetLastError());

            return -1;

        }

        else

            printf("sendto() is OK!\n");

 

        // Waite for a response

        rc = WaitForSingleObject((HANDLE)recvol.hEvent, DEFAULT_RECV_TIMEOUT);

        if (rc == WAIT_FAILED)

        {

            fprintf(stderr, "WaitForSingleObject() failed with error code %d\n", GetLastError());

            return -1;

        }

        else if (rc == WAIT_TIMEOUT)

        {

            printf("Request timed out.\n");

        }

        else

        {

            printf("WaitForSingleObject() looks OK!\n");

            rc = WSAGetOverlappedResult(s, &recvol, &bytes, FALSE, &flags);

            if (rc == FALSE)

            {

                fprintf(stderr, "WSAGetOverlappedResult() failed with error code %d\n", WSAGetLastError());

            }

            else

                printf("WSAGetOverlappedResult() is OK!\n");

 

            time = time - GetTickCount();

 

            WSAResetEvent(recvol.hEvent);

 

            printf("Reply from ");

            PrintAddress((SOCKADDR *)&from, fromlen);

            if (time == 0)

                printf(": bytes=%d time<1ms TTL=%d\n", gDataSize, gTtl);

            else

                printf(": bytes=%d time=%dms TTL=%d\n", gDataSize, time, gTtl);

 

            PrintPayload(recvbuf, bytes);

 

            if (i < DEFAULT_SEND_COUNT)

            {

                fromlen = sizeof(from);

                PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, &recvol);

            }

        }

        Sleep(1000);

    }

 

    // Cleanup

    printf("Clean up steps....\n");

    freeaddrinfo(dest);

    freeaddrinfo(local);

 

    if (s != INVALID_SOCKET)

        closesocket(s);

    HeapFree(GetProcessHeap(), 0, icmpbuf);

 

    WSACleanup();

    return 0;

}

 

Add the iphdrv2.h header file

 

-------------------------------------------------------------

IPv4 and IPv6 Ping Program Example: Adding iphdrv2.h header file to the project.

 

Add the source code.

 

// Sample: Protocol header definitions used by ping (raw sockets)

//

// Files:

//      iphdrv2.h     - this file

//

// Description:

//      This file contains various protocol header definitions used by

//      the raw socket ping sample.

//

// Align on a 1-byte boundary

#include <pshpack1.h>

 

// IPv4 header

typedef struct ip_hdr

{

    unsigned char  ip_verlen;          // 4-bit IPv4 version 4-bit header length (in 32-bit words)

    unsigned char  ip_tos;               // IP type of service

    unsigned short ip_totallength;   // Total length

    unsigned short ip_id;                 // Unique identifier

    unsigned short ip_offset;           // Fragment offset field

    unsigned char  ip_ttl;                  // Time to live

    unsigned char  ip_protocol;       // Protocol(TCP,UDP etc)

    unsigned short ip_checksum;    // IP checksum

    unsigned int   ip_srcaddr;           // Source address

    unsigned int   ip_destaddr;         // Source address

} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;

 

// IPv4 option header

typedef struct ipv4_option_hdr

{

    unsigned char   opt_code;        // option type

    unsigned char   opt_len;            // length of the option header

    unsigned char   opt_ptr;            // offset into options

    unsigned long   opt_addr[9];     // list of IPv4 addresses

} IPV4_OPTION_HDR, *PIPV4_OPTION_HDR, FAR *LPIPV4_OPTION_HDR;

 

// ICMP header

typedef struct icmp_hdr

{

    unsigned char   icmp_type;

    unsigned char   icmp_code;

    unsigned short  icmp_checksum;

    unsigned short  icmp_id;

    unsigned short  icmp_sequence;

    unsigned long   icmp_timestamp;

} ICMP_HDR, *PICMP_HDR, FAR *LPICMP_HDR;

 

// IPv6 protocol header

typedef struct ipv6_hdr

{

    unsigned long   ipv6_vertcflow;        // 4-bit IPv6 version, 8-bit traffic class, 20-bit flow label

    unsigned short  ipv6_payloadlen;    // payload length

    unsigned char   ipv6_nexthdr;          // next header protocol value

    unsigned char   ipv6_hoplimit;         // TTL

    struct in6_addr ipv6_srcaddr;          // Source address

    struct in6_addr ipv6_destaddr;         // Destination address

} IPV6_HDR, *PIPV6_HDR, FAR * LPIPV6_HDR;

 

// IPv6 fragment header

typedef struct ipv6_fragment_hdr

{

    unsigned char   ipv6_frag_nexthdr;

    unsigned char   ipv6_frag_reserved;

    unsigned short  ipv6_frag_offset;

    unsigned long   ipv6_frag_id;

} IPV6_FRAGMENT_HDR, *PIPV6_FRAGMENT_HDR, FAR * LPIPV6_FRAGMENT_HDR;

 

// ICMPv6 header

typedef struct icmpv6_hdr {

    unsigned char   icmp6_type;

    unsigned char   icmp6_code;

    unsigned short  icmp6_checksum;

} ICMPV6_HDR;

 

// ICMPv6 echo request body

typedef struct icmpv6_echo_request

{

    unsigned short  icmp6_echo_id;

    unsigned short  icmp6_echo_sequence;

} ICMPV6_ECHO_REQUEST;

 

// Define the UDP header

typedef struct udp_hdr

{

    unsigned short src_portno;       // Source port no.

    unsigned short dst_portno;       // Dest. port no.

    unsigned short udp_length;       // Udp packet length

    unsigned short udp_checksum;     // Udp checksum (optional)

} UDP_HDR, *PUDP_HDR;

 

// IPv4 option for record route

#define IP_RECORD_ROUTE     0x7

 

// ICMP6 protocol value (used in the socket call and IPv6 header)

#define IPPROTO_ICMP6       58

 

// ICMP types and codes

#define ICMPV4_ECHO_REQUEST_TYPE   8

#define ICMPV4_ECHO_REQUEST_CODE   0

#define ICMPV4_ECHO_REPLY_TYPE     0

#define ICMPV4_ECHO_REPLY_CODE     0

#define ICMPV4_MINIMUM_HEADER      8

 

// ICPM6 types and codes

#define ICMPV6_ECHO_REQUEST_TYPE   128

#define ICMPV6_ECHO_REQUEST_CODE   0

#define ICMPV6_ECHO_REPLY_TYPE     129

#define ICMPV6_ECHO_REPLY_CODE     0

 

// Restore byte alignment back to default

#include <poppack.h>

 

Add the resolve.h and its definition files into this project which were created in the previous project.

 

IPv4 and IPv6 Ping Program Example: Copying the header and its definition files.

 

IPv4 and IPv6 Ping Program Example: Pasting the header and its definition files.

 

 

 

 

IPv4 and IPv6 Ping Program Example: Adding the header and its definition files to the existing project.

 

 

IPv4 and IPv6 Ping Program Example: Selecting the header and its definition files.

 

IPv4 and IPv6 Ping Program Example: The added header and its definition files seen in Solution explorer.

 

Build and run the project.

 

IPv4 and IPv6 Ping Program Example: A sample output without any argument

 

ipv4ipv6pingexample -a 4 -l 64 -r www.google.com

 

IPv4 and IPv6 Ping Program Example: A sample output with IPv4 argument

 

ipv4ipv6pingexample -a 6 www.ipv6.org

 

IPv4 and IPv6 Ping Program Example: A sample output with IPv6 argument

 

The following screenshots shows the Windows ping6 utility program with its’ options/switches.

 

IPv4 and IPv6 Ping Program Example: The windows ping6 utility options

 

One noticeable feature of the Ping example is its use of the IP_OPTIONS socket option. We use the record route IPv4 option so that when the ICMP packet hits a router, its IPv4 address is added into the IPv4 option header at the location indicated by the offset field in the IPv4 option header. This offset is also incremented by four each time a router adds its address. The increment value is based on the fact that an IPv4 address is 4 bytes long. Once you receive the echo reply, decode the option header and print the IP addresses and host names of the routers visited.

 

 

 


< RAW Socket, ICMP & Ping | RAW Socket Main | Traceroute Program Example >