< IP Header Include Option | RAW Socket Main | UDP RAW Socket Example (continue) >


 

 

Raw Sockets 11 Part 5

 

 

What do we have in this chapter 11 part 5?

  1. Program Examples: The UDP RAW Socket

 

Program Examples: The UDP RAW Socket

 

Create a new empty Win32 console mode application and add the project/solution name.

 

Program Examples: The UDP RAW Socket: Creating a new empty Win32 console mode application project

 

Add the following source code.

 

// Sample: Raw IPv4/IPv6 UDP with IP_HDRINCL option

//

// Files:

//      rawudpexamplesrc.cpp    - this file

//      iphdr.h       - IPv4, IPv6, and UDP header structure definitions

//      resolve.cpp   - common name resolution routines

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

//

// Description:

//    This is a simple app that demonstrates the usage of the

//    IP_HDRINCL socket option. A raw socket is created of the

//    UDP protocol where we will build our own IP and UDP header

//    that we submit to sendto().//

//    For IPv4 this is fairly simple. Create a raw socket, set the

//    IP_HDRINCL option, build the IPv4 and UDP headers, and do a

//    sendto. The IPv4 stack will fragment the data as necessary and

//    generally leaves the packet unmodified -- it performs fragmentation

//    and sets the IPv4 ID field.//

//    For IPv6 its a bit more involved as it does not perform any

//    fragmentation, you have to do it and build the headers yourself.//

//    The IP_HDRINCL option only works on Windows 2000 or greater.

//

// Usage:

//      rawudpexample [options]

//          -a  4|6    Address family

//          -sa addr   From (sender) IP address

//          -sp int    From (sender) port number

//          -da addr   To (recipient) IP address

//          -dp int    To (recipient) port number

//          -n  int    Number of times to read message

//          -m  str    String message to fill packet data with

//          -p  proto  Protocol value

//          -r  port   Receive raw (SOCK_RAW) datagrams on the given port

//          -rd port   Receive datagram (SOCK_DGRAM) on the given port

//          -t  mtu    MTU size (required for fragmentation)

//          -z  int    Size of message to send

//

#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 "iphdr.h"

 

// Setup some default values

#define DEFAULT_MTU           1496          // default MTU size

#define DEFAULT_TTL           8             // default TTL value

 

#define MAX_PACKET            65535         // maximum datagram size

#define MAX_PACKET_FRAGMENTS ((MAX_PACKET / DEFAULT_MTU) + 1)

 

#define DEFAULT_PORT          5150          // default port to send to

#define DEFAULT_COUNT         5             // default number of messages to send

#define DEFAULT_MESSAGE       "This is a test string!"  // default message

 

#define FRAGMENT_HEADER_PROTOCOL    44      // protocol value for IPv6 fragmentation header

 

// Global variables

char     *gSrcAddress=NULL,          // IP address to send from

         *gDestAddress=NULL,           // IP address to send to

         *gSrcPort=NULL,                     // port to send from

         *gDestPort=NULL,                   // port to send to

         *gMessage=NULL;                  // Message to send as UDP payload

int       gAddressFamily=AF_UNSPEC,

          gSocketType=SOCK_DGRAM,    // Socket type to pass to name resolution routines

          gProtocol=IPPROTO_UDP,     // Protocol value that we're sending

          gSendSize=0,                            // Data size of message to send

          gMtuSize=DEFAULT_MTU;    // Maximum transmission unit to use

DWORD     gSendCount;                   // number of times to send

BOOL      bSender=TRUE,                // sending or receiving data

          bReadRaw=TRUE;                  // Use raw sockets when reading

 

// Function: usage:

// Description: Print usage information and exit.

int usage(char *progname)

{

    printf("Usage: %s [-fp int] [-fi str] [-tp int] [-ti str] [-n int] [-m str]\n"

           "    -a  4|6    Address family\n"

           "    -sa addr   From (sender) IP address\n"

           "    -sp int    From (sender) port number\n"

           "    -da addr   To (recipient) IP address\n"

           "    -dp int    To (recipient) port number\n"

           "    -n  int    Number of times to read message\n"

           "    -m  str    String message to fill packet data with\n"

           "    -p  proto  Protocol value\n"

           "    -r  port   Receive raw (SOCK_RAW) datagrams on the given port\n"

           "    -rd port   Receive datagram (SOCK_DGRAM) on the given port\n"

           "    -t  mtu    MTU size (required for fragmentation)\n"

           "    -z  int    Size of message to send\n",

           progname

           );

    return 0;

}

 

// Function: ValidateArgs

// Description:

//    Parse the command line arguments and set some global flags to indicate what actions to perform.

void ValidateArgs(int argc, char **argv)

{

    int    i;

 

    gMessage = DEFAULT_MESSAGE;

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

    {

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

        {

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

            {

                printf("i = %d\n", i);

                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 's':      // source address

                    if (i+1 > argc)

                    {

                        printf("i + 1 = %d\n", i + 1);

                        usage(argv[0]);

                    }

                    if (tolower(argv[i][2]) == 'a')

                    {

                        gSrcAddress = argv[++i];

                    }

                    else if (tolower(argv[i][2]) == 'p')

                    {

                        gSrcPort = argv[++i];

                    }

                    else

                    {

                        usage(argv[0]);

                        break;

                    }

                    break;

                case 'd':      // destination address

                    if (i+1 > argc)

                    {

                        printf("i + 1 = %d\n", i + 1);

                        usage(argv[0]);

                    }

                    if (tolower(argv[i][2]) == 'a')

                    {

                        gDestAddress = argv[++i];

                    }

                    else if (tolower(argv[i][2]) == 'p')

                    {

                        gDestPort = argv[++i];

                    }

                    else

                    {

                        usage(argv[0]);

                        break;

                    }

                    break;

                case 'n':      // number of times to send message

                    if (i+1 >= argc)

                        usage(argv[0]);

                    gSendCount = atol(argv[++i]);

                    break;     // String message to copy into payload

                case 'm':

                    if (i+1 >= argc)

                        usage(argv[0]);

                    gMessage = argv[++i];

                    break;

                case 'p':      // Protocol value

                    if (i+1 >= argc)

                        usage(argv[0]);

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

                    break;

                case 'r':       // Port to receive data on

                    if (i+1 >= argc)

                        usage(argv[0]);

                    if (strlen(argv[i]) == 3)

                        bReadRaw = FALSE;

                    gSrcPort = argv[++i];

                    bSender = FALSE;

                    break;

                case 't':       // MTU size

                    if (i+1 >= argc)

                        usage(argv[0]);

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

                    break;

                case 'z':      // Send size

                    if (i+1 >= argc)

                        usage(argv[0]);

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

                    break;

                default:

                    usage(argv[0]);

                    break;

            }

        }

    }

    // If no data size was given, initialize it to the message supplied

    if (gSendSize == 0)

    {

        gSendSize = strlen(gMessage);

    }

    return;

}

 

// Function: checksum

// Description: This function calculates the 16-bit one's complement sum for the supplied buffer.

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: InitIpv4Header

// Description:

//    Initialize the IPv4 header with the version, header length,

//    total length, ttl, protocol value, and source and destination addresses

int InitIpv4Header(char *buf, SOCKADDR *src, SOCKADDR *dest, int ttl, int proto, int payloadlen)

{

    IPV4_HDR    *v4hdr=NULL;

 

    v4hdr = (IPV4_HDR *)buf;

 

    v4hdr->ip_verlen      = (4 << 4) | (sizeof(IPV4_HDR) / sizeof(unsigned long));

    v4hdr->ip_tos         = 0;

    v4hdr->ip_totallength = htons(sizeof(IPV4_HDR) + payloadlen);

    v4hdr->ip_id          = 0;

    v4hdr->ip_offset      = 0;

    v4hdr->ip_ttl         = (unsigned char)ttl;

    v4hdr->ip_protocol    = (unsigned char)proto;

    v4hdr->ip_checksum    = 0;

    v4hdr->ip_srcaddr     = ((SOCKADDR_IN *)src)->sin_addr.s_addr;

    v4hdr->ip_destaddr    = ((SOCKADDR_IN *)dest)->sin_addr.s_addr;

 

    v4hdr->ip_checksum    = checksum((unsigned short *)v4hdr, sizeof(IPV4_HDR));

 

    return sizeof(IPV4_HDR);

}

 

// Function: InitIpv6Header

// Description:

//    Initialize the IPv6 header with the version, payload length, next

//    hop protocol, TTL, and source and destination addresses.

int InitIpv6Header(char *buf, SOCKADDR *src, SOCKADDR *dest, int ttl, int proto, int payloadlen)

{

    IPV6_HDR    *v6hdr=NULL;

 

    v6hdr = (IPV6_HDR *)buf;

 

    // We don't explicitly set the traffic class or flow label fields

    v6hdr->ipv6_vertcflow    = htonl(6 << 28);

    v6hdr->ipv6_payloadlen   = htons((unsigned short)payloadlen);

    v6hdr->ipv6_nexthdr      = (unsigned char)proto;

    v6hdr->ipv6_hoplimit     = (unsigned char)ttl;

    v6hdr->ipv6_srcaddr      = ((SOCKADDR_IN6 *)src)->sin6_addr;

    v6hdr->ipv6_destaddr     = ((SOCKADDR_IN6 *)dest)->sin6_addr;

 

    return sizeof(IPV6_HDR);

}

 

// Function: InitIpv6FragmentHeader

// Description:

//    Initialize the IPv6 fragmentation header. The offset is the offset

//    from the start of the IPv6 total payload (which includes the UDP

//    header along with the data) which is why we add the length of

//    the UDP header if this fragment is not the first fragment. Also,

//    the lastfragment parameter is a boolean value (0 == not the last

//    fragment while 1 == this is the last fragment) which is the opposite

//    value that is supposed to be indicated in the header (i.e. 0 indicates

//    that this fragment is the last fragment).

int InitIpv6FragmentHeader(char *buf, unsigned long offset, int nextproto, int id, int lastfragment)

{

    IPV6_FRAGMENT_HDR *frag=NULL;

 

    frag = (IPV6_FRAGMENT_HDR *)buf;

 

    // Swap the value of this field

    lastfragment = (lastfragment ? 0 : 1);

 

    // Account for the size of the UDP header

    if (offset != 0)

        offset += sizeof(UDP_HDR);

 

    frag->ipv6_frag_nexthdr = (unsigned char)nextproto;

    frag->ipv6_frag_offset  = htons( (unsigned short)(((offset/8) << 3) | lastfragment));

    frag->ipv6_frag_id      = htonl(id);

 

    return sizeof(IPV6_FRAGMENT_HDR);

}

 

// Function: InitUdpHeader

// Description:

//    Setup the UDP header which is fairly simple. Grab the ports and

//    stick in the total payload length.

int InitUdpHeader(char *buf, SOCKADDR *src, SOCKADDR *dest, int payloadlen)

{

    UDP_HDR *udphdr=NULL;

 

    udphdr = (UDP_HDR *)buf;

 

    // Port numbers are already in network byte order

    if (src->sa_family == AF_INET)

    {

        udphdr->src_portno = ((SOCKADDR_IN *)src)->sin_port;

        udphdr->dst_portno = ((SOCKADDR_IN *)dest)->sin_port;

    }

    else if (src->sa_family == AF_INET6)

    {

        udphdr->src_portno = ((SOCKADDR_IN6 *)src)->sin6_port;

        udphdr->dst_portno = ((SOCKADDR_IN6 *)dest)->sin6_port;

    }

    udphdr->udp_length = htons(sizeof(UDP_HDR) + payloadlen);

 

    return sizeof(UDP_HDR);

}

// Function: ComputeUdpPseudoHeaderChecksumV4

// Description:

//    Compute the UDP pseudo header checksum. The UDP checksum is based

//    on the following fields:

//       - source IP address

//       - destination IP address

//       - 8-bit zero field

//       - 8-bit protocol field

//       - 16-bit UDP length

//       - 16-bit source port

//       - 16-bit destination port

//       - 16-bit UDP packet length

//       - 16-bit UDP checksum (zero)

//       - UDP payload (padded to the next 16-bit boundary)

//    This routine copies these fields to a temporary buffer and computes

//    the checksum from that.

void ComputeUdpPseudoHeaderChecksumV4(void *iphdr, UDP_HDR *udphdr, char *payload, int payloadlen)

{

    IPV4_HDR     *v4hdr=NULL;

    unsigned long zero=0;

    char          buf[MAX_PACKET], *ptr=NULL;

    int           chksumlen=0, i;

 

    ptr = buf;

    v4hdr = (IPV4_HDR *)iphdr;

    // Include the source and destination IP addresses

    memcpy(ptr, &v4hdr->ip_srcaddr,  sizeof(v4hdr->ip_srcaddr));

    ptr += sizeof(v4hdr->ip_srcaddr);

    chksumlen += sizeof(v4hdr->ip_srcaddr);

 

    memcpy(ptr, &v4hdr->ip_destaddr, sizeof(v4hdr->ip_destaddr));

    ptr += sizeof(v4hdr->ip_destaddr);

    chksumlen += sizeof(v4hdr->ip_destaddr);

    // Include the 8 bit zero field

    memcpy(ptr, &zero, 1);

    ptr++;

    chksumlen += 1;

    // Protocol

    memcpy(ptr, &v4hdr->ip_protocol, sizeof(v4hdr->ip_protocol));

    ptr += sizeof(v4hdr->ip_protocol);

    chksumlen += sizeof(v4hdr->ip_protocol);

    // UDP length

    memcpy(ptr, &udphdr->udp_length, sizeof(udphdr->udp_length));

    ptr += sizeof(udphdr->udp_length);

    chksumlen += sizeof(udphdr->udp_length);

    // UDP source port

    memcpy(ptr, &udphdr->src_portno, sizeof(udphdr->src_portno));

    ptr += sizeof(udphdr->src_portno);

    chksumlen += sizeof(udphdr->src_portno);

    // UDP destination port

    memcpy(ptr, &udphdr->dst_portno, sizeof(udphdr->dst_portno));

    ptr += sizeof(udphdr->dst_portno);

    chksumlen += sizeof(udphdr->dst_portno);

    // UDP length again

    memcpy(ptr, &udphdr->udp_length, sizeof(udphdr->udp_length));

    ptr += sizeof(udphdr->udp_length);

    chksumlen += sizeof(udphdr->udp_length);

    // 16-bit UDP checksum, zero

    memcpy(ptr, &zero, sizeof(unsigned short));

    ptr += sizeof(unsigned short);

    chksumlen += sizeof(unsigned short);

    // payload

    memcpy(ptr, payload, payloadlen);

    ptr += payloadlen;

    chksumlen += payloadlen;

    // pad to next 16-bit boundary

    for(i=0 ; i < payloadlen%2 ; i++, ptr++)

    {

        printf("pad one byte\n");

        *ptr = 0;

        ptr++;

        chksumlen++;

    }

 

    // Compute the checksum and put it in the UDP header

    udphdr->udp_checksum = checksum((USHORT *)buf, chksumlen);

 

    return;

}

 

void ComputeUdpPseudoHeaderChecksumV6(void *iphdr, UDP_HDR *udphdr, char *payload, int payloadlen)

{

    IPV6_HDR     *v6hdr=NULL;

    unsigned long length=0;

    char          buf[MAX_PACKET], proto, *ptr=NULL;

    int           chksumlen=0, i;

 

    ptr = buf;

    v6hdr = (IPV6_HDR *)iphdr;

 

    memcpy(ptr, &v6hdr->ipv6_srcaddr,  sizeof(v6hdr->ipv6_srcaddr));

    ptr += sizeof(v6hdr->ipv6_srcaddr);

    chksumlen += sizeof(v6hdr->ipv6_srcaddr);

 

    memcpy(ptr, &v6hdr->ipv6_destaddr,  sizeof(v6hdr->ipv6_destaddr));

    ptr += sizeof(v6hdr->ipv6_destaddr);

    chksumlen += sizeof(v6hdr->ipv6_destaddr);

 

    printf("payload length = %d\n", payloadlen);

    length = htonl(payloadlen + sizeof(UDP_HDR));

 

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

    ptr += sizeof(length);

    chksumlen += sizeof(length);

 

    memset(ptr, 0, 3);

    ptr += 3;

    chksumlen +=3;

 

    proto = IPPROTO_UDP;

 

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

    ptr += sizeof(proto);

    chksumlen += sizeof(proto);

 

    // UDP source port

    memcpy(ptr, &udphdr->src_portno, sizeof(udphdr->src_portno));

    ptr += sizeof(udphdr->src_portno);

    chksumlen += sizeof(udphdr->src_portno);

    // UDP destination port

    memcpy(ptr, &udphdr->dst_portno, sizeof(udphdr->dst_portno));

    ptr += sizeof(udphdr->dst_portno);

    chksumlen += sizeof(udphdr->dst_portno);

    // UDP length again

    memcpy(ptr, &udphdr->udp_length, sizeof(udphdr->udp_length));

    ptr += sizeof(udphdr->udp_length);

    chksumlen += sizeof(udphdr->udp_length);

    // 16-bit UDP checksum, zero

    memset(ptr, 0, sizeof(unsigned short));

    ptr += sizeof(unsigned short);

    chksumlen += sizeof(unsigned short);

    // payload

    memcpy(ptr, payload, payloadlen);

    ptr += payloadlen;

    chksumlen += payloadlen;

    // pad to next 16-bit boundary

    for(i=0 ; i < payloadlen%2 ; i++, ptr++)

    {

        printf("pad one byte\n");

        *ptr = 0;

        ptr++;

        chksumlen++;

    }

    // Compute the checksum and put it in the UDP header

    udphdr->udp_checksum = checksum((USHORT *)buf, chksumlen);

 

    return;

}

 

// Function: memfill

// Description: Fills a block of memory with a given string pattern.

void memfill(char *dest, int   destlen, char *data, int   datalen)

{

    char *ptr=NULL;

    int   copylen;

 

    ptr = dest;

    while (destlen > 0)

    {

        copylen = ((destlen > datalen) ? datalen : destlen);

        memcpy(ptr, data, copylen);

 

        destlen -= copylen;

        ptr += copylen;

    }

    return;

}

 

// Function: PacketizeIpv4

// Description:

//    This routine takes the data buffer and packetizes it for IPv4.

//    Since the IPv4 stack takes care of fragmentation for us, this

//    routine simply initializes the IPv4 and UDP headers. The data

//    is returned in an array of WSABUF structures.

WSABUF *PacketizeIpv4(struct addrinfo *src, struct addrinfo *dest, char *payload, int payloadlen)

{

    static WSABUF Packets[MAX_PACKET_FRAGMENTS];

    int           iphdrlen, udphdrlen;

 

    // Allocate memory for the packet

    Packets[0].buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IPV4_HDR) + sizeof(UDP_HDR) + payloadlen);

    if (Packets[0].buf == NULL)

    {

        fprintf(stderr, "PacetizeV4: HeapAlloc failed: %d\n", GetLastError());

        ExitProcess(-1);

    }

    Packets[0].len = sizeof(IPV4_HDR) + sizeof(UDP_HDR) + payloadlen;

    // Initialize the v4 header

    iphdrlen = InitIpv4Header(Packets[0].buf, src->ai_addr, dest->ai_addr, DEFAULT_TTL, gProtocol, payloadlen);

    // Initialize the UDP header

    udphdrlen = InitUdpHeader(&Packets[0].buf[iphdrlen], src->ai_addr, dest->ai_addr, payloadlen);

    // Compute the UDP checksum

    ComputeUdpPseudoHeaderChecksumV4(Packets[0].buf,(UDP_HDR *)&Packets[0].buf[iphdrlen],payload,payloadlen);

    // Copy the payload to the end of the header

    memcpy(&Packets[0].buf[iphdrlen + udphdrlen], payload, payloadlen);

    // Zero out the next WSABUF structure which indicates the end of

    //    the packets -- caller must free the buffers

    Packets[1].buf = NULL;

    Packets[1].len = 0;

 

    return Packets;

}

 

// Function: PacketizeIpv6

// Description:

//    This routine fragments data payload with the appropriate IPv6

//    headers. The individual fragments are returned via an array of

//    WSABUF structures. Each structure is a separate fragment of the

//    whole message. The end of the fragments is indicated by a WSABUF

//    entry with a NULL buffer pointer.

WSABUF *PacketizeIpv6(struct addrinfo *src, struct addrinfo *dest, char *payload, int payloadlen)

{

    static WSABUF Packets[MAX_PACKET_FRAGMENTS];

    static ULONG  fragid=1;

    int           offset=0,           // offset into payload

                  datalen,             // length of the payload

                  hdrlen,               // length of the header(s)

                  fragment,          // is this a fragment?

                  lastfragment,    // is this the last fragment?

                  iphdrlen,           // length of ip header

                  udphdrlen,        // length of the udp header

                  plushdrs,           // IPv6 length field includes encapsulated headers

                  numpackets=0, // number of fragments

                  originalpayload;

 

    originalpayload = payloadlen;

    do

    {

        // Compute the size of this fragment

        lastfragment = 0;

        fragment = 0;

        if ((payloadlen > gMtuSize) && (numpackets == 0))

        {

            // Data needs to be fragmented, this is the first packet

            hdrlen  = sizeof(IPV6_HDR) + sizeof(UDP_HDR) + sizeof(IPV6_FRAGMENT_HDR);

            datalen = gMtuSize - hdrlen;

            plushdrs = sizeof(UDP_HDR) + sizeof(IPV6_FRAGMENT_HDR);

            fragment = 1;

 

            printf("Require fragmentation: FIRST packet\n");

        }

        else if ((payloadlen > gMtuSize) && (numpackets > 0))

        {

            // Data needs to be fragmented, this is packet number > 0

            hdrlen = sizeof(IPV6_HDR) + sizeof(IPV6_FRAGMENT_HDR);

            datalen = gMtuSize - hdrlen;

            fragment = 1;

            plushdrs = sizeof(IPV6_FRAGMENT_HDR);

 

            printf("Require fragmentation: packet number > 0\n");

        }

        else if (numpackets == 0)

        {

            // Data doesn't need to be fragmented

            hdrlen = sizeof(IPV6_HDR) + sizeof(UDP_HDR);

            datalen = payloadlen;

            fragment = 0;

            plushdrs = sizeof(UDP_HDR);

 

            printf("No fragmentation required\n");

        }

        else

        {

            // This is the last fragment

            hdrlen = sizeof(IPV6_HDR) + sizeof(IPV6_FRAGMENT_HDR);

            datalen = payloadlen;

            fragment = 1;

            plushdrs = sizeof(IPV6_FRAGMENT_HDR);

            lastfragment = 1;

            printf("Require fragmentation: Last packet\n");

        }

        // Build packet

        // Allocate buffer for this fragment

        Packets[numpackets].buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hdrlen + datalen);

        if (Packets[numpackets].buf == NULL)

        {

            fprintf(stderr, "PacketizeV6: HeapAlloc failed: %d\n", GetLastError());

            ExitProcess(-1);

        }

        Packets[numpackets].len = hdrlen + datalen;

 

        // Initialize the V6 header, if we have to fragment the next header field of

        //    the v6 header is that of the fragmentation header. Also the payload

        //    length includes the headers (UDP + fragmentation) and the payload itself.

        iphdrlen = InitIpv6Header(

                Packets[numpackets].buf,

                src->ai_addr,

                dest->ai_addr,

                DEFAULT_TTL,

                (fragment ? FRAGMENT_HEADER_PROTOCOL : gProtocol),

                datalen + plushdrs

                );

 

        // Build the fragmentation header if necessary

        if (fragment)

        {

            iphdrlen += InitIpv6FragmentHeader(

                   &Packets[numpackets].buf[iphdrlen],

                    offset,         // offset from start of packet

                    gProtocol,

                    fragid,

                    lastfragment

                    );

        }

 

        // The first fragment includes the UDP header, subsequent fragments don't

        if (numpackets == 0)

        {

            udphdrlen = InitUdpHeader(

                   &Packets[numpackets].buf[iphdrlen],

                    src->ai_addr,

                    dest->ai_addr,

                    originalpayload // payloadlen

                    );

            // Compute the checksum

            ComputeUdpPseudoHeaderChecksumV6(

                    Packets[numpackets].buf,

                    (UDP_HDR *)&Packets[numpackets].buf[iphdrlen],

                    payload,

                    payloadlen);

        }

        else

        {

            udphdrlen = 0;

        }

        // Copy the payload into this fragment

        memcpy(&Packets[numpackets].buf[iphdrlen + udphdrlen], &payload[offset], datalen);

        // Adjust our counters

        payloadlen = payloadlen - datalen;

        offset += datalen;

        numpackets++;

    } while (payloadlen > 0);

 

    fragid++;

 

    // Mark the next WSABUF entry with NULL and zero to indicate end of fragments

    Packets[numpackets].buf = NULL;

    Packets[numpackets].len = 0;

 

    return Packets;

}

 

// Function: main

// Description:

//    First, parse command line arguments and load Winsock. Then

//    create the raw socket and then set the IP_HDRINCL option.

//    Following this assemble the IP and UDP packet headers by

//    assigning the correct values and calculating the checksums.

//    Then fill in the data and send to its destination.

int main(int argc, char **argv)

{

    WSADATA            wsd;

    SOCKET             s;

    DWORD              bytes;

    WSABUF            *wbuf=NULL;

    struct addrinfo   *ressrc=NULL, *resdest=NULL, *resbind=NULL;

    int                packets, rc,i, j;

 

    if(argc < 2)

    {

        usage(argv[0]);

        exit(1);

    }

 

    // Parse command line arguments and print them out

    ValidateArgs(argc, argv);

 

    srand(GetTickCount());

 

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

    {

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

        return -1;

    }

    else

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

    // Convert the source and destination addresses/ports

    ressrc = ResolveAddress(gSrcAddress, gSrcPort, gAddressFamily, gSocketType, gProtocol);

    if (ressrc == NULL)

    {

        fprintf(stderr, "Unable to resolve address '%s' and port '%s'\n", gSrcAddress, gSrcPort);

        return -1;

    }

    else

        printf("ResolveAddress(): Address resolved!\n");

 

    if (bSender)

    {

        resdest = ResolveAddress(gDestAddress, gDestPort, ressrc->ai_family, ressrc->ai_socktype, ressrc->ai_protocol);

        if (resdest == NULL)

        {

            fprintf(stderr, "Unable to resolve address '%s' and port '%s'\n",

                    gDestAddress, gDestPort);

            return -1;

        }

        else

            printf("ResolveAddress(): Address resolved!\n");

    }

 

    //  Creating a raw socket

    //  BUG - For IPv6 if we create the raw socket with IPPROTO_UDP then the Ipv6

    //  stack will throw away our IPv6 and UDP headers and put "valid" ones in their

    //  place. As a workaround, create the socket with a protocol value of an

    //  unhandled protocol. Of course the IPv6 header should still indicate that

    //  the encapsulated protocol is UDP.

    if (bSender)

        s = socket(ressrc->ai_family, SOCK_RAW, ((ressrc->ai_family == AF_INET6) ? 3 : ressrc->ai_protocol));

    else if (!bSender && bReadRaw)

        s = socket(ressrc->ai_family, SOCK_RAW, ressrc->ai_protocol);

    else

        s = socket(ressrc->ai_family, SOCK_DGRAM, ressrc->ai_protocol);

    if (s == INVALID_SOCKET)

    {

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

        return -1;

    }

    else

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

 

    if (bSender)

    {

        char   *payload=NULL;

        int     optlevel, option, optval;

 

        payload = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, gSendSize);

        if (payload == NULL)

        {

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

            return -1;

        }

        else

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

 

        memfill(payload, gSendSize, gMessage, strlen(gMessage));

        // Enable the IP header include option

        optval = 1;

        if (ressrc->ai_family == AF_INET)

        {

            optlevel = IPPROTO_IP;

            option   = IP_HDRINCL;

        }

        else if (ressrc->ai_family == AF_INET6)

        {

            optlevel = IPPROTO_IPV6;

            option   = IPV6_HDRINCL;

        }

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

        if (rc == SOCKET_ERROR)

        {

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

            return -1;

        }

        else

            printf("setsockopt() for IP_HDRINCL is OK!\n");

 

        // Packetize and/or perform necessary fragmentation on data

        if (ressrc->ai_family == AF_INET)

        {

            wbuf = PacketizeIpv4(ressrc, resdest, payload, gSendSize);

        }

        else if (ressrc->ai_family == AF_INET6)

        {

            wbuf = PacketizeIpv6(ressrc,resdest, payload, gSendSize);

        }

 

        // Count how many packets there are

        i=0;

        packets=0;

        while (wbuf[i].buf)

        {

            printf("packet %d buf 0x%p len %d\n", i, wbuf[i].buf, wbuf[i].len);

            packets++;

            i++;

        }

 

        // Apparently, this SOCKADDR_IN structure makes no difference.

        // Whatever we put as the destination IP addr in the IP

        // header is what goes. Specifying a different dest in remote

        // will be ignored.

        for(i=0; i < (int)gSendCount ;i++)

        {

            for(j=0; j < packets ;j++)

            {

                rc = sendto(s, wbuf[j].buf, wbuf[j].len, 0, resdest->ai_addr, resdest->ai_addrlen);

                bytes = rc;

                if (rc == SOCKET_ERROR)

                {

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

                    break;

                }

                else

                {

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

                    printf("sent %d bytes\n", bytes);

                }

            }

        }

 

        // Free the packet buffers

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

        {

            HeapFree(GetProcessHeap(), 0, wbuf[i].buf);

        }

    }

    else

    {

        SOCKADDR_STORAGE    safrom;

        char                buf[MAX_PACKET];

        int                 fromlen;

 

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

        if (rc == SOCKET_ERROR)

        {

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

            return -1;

        }

        else

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

 

        printf("binding to: ");

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

        printf("\n");

 

        while (1)

        {

            fromlen = sizeof(safrom);

            rc = recvfrom(s, buf, MAX_PACKET, 0, (SOCKADDR *)&safrom, &fromlen);

            if (rc == SOCKET_ERROR)

            {

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

                break;

            }

            else

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

 

            printf("Read %d bytes from ", rc);

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

            printf("\n");

        }

    }

    closesocket(s) ;

    WSACleanup() ;

    return 0;

}

 

 

 


< IP Header Include Option | RAW Socket Main | UDP RAW Socket Example (continue) >