< UDP RAW Socket Example | RAW Socket Main | Chap 12: Remote Access Service (RAS) >


 

 

Raw Sockets 11 Part 6

 

 

What do we have in this chapter 11 part 6?

  1. Program Examples: The UDP RAW Socket (continue)

 

Add the iphdr.h header file to the project.

 

Using IP Header Include Option Program Examples: Adding the iphdr.h header file to the project

 

Add the following source code.

 

// Sample: Header definitions for raw UDP sample (IP_HDRINCL option)

// Files:

//      iphdr.h     - this file

// Description:

//      This file contains the header definitions for the IPv4, IPv6, UDP,

//      fragment headers, etc. which are used by the raw UDP sample.

//

// Set the packing to a 1 byte boundary

#include <pshpack1.h>

 

// Define the IPv4 header. Make the version and length field one

// character since we can't declare two 4 bit fields without

// the compiler aligning them on at least a 1 byte boundary.

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;

 

// IPv6 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;

 

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

 

// Restore the byte boundary back to the previous value

#include <poppack.h>

 

 

 

 

Add the resolve.h header file.

 

Using IP Header Include Option Program Examples: Adding the resolve header file to the project

 

Add the following source code.

 

// Common routines for resolving addresses and hostnames

// Files:

//      resolve.h       - Header file for common routines

// Description:

//      This file contains common name resolution and name printing

//      routines and is used by many of the samples on this CD.

//

#ifndef _RESOLVE_H_

#define _RESOLVE_H_

 

#ifdef _cplusplus

extern "C" {

#endif

 

int              PrintAddress(SOCKADDR *sa, int salen);

int              FormatAddress(SOCKADDR *sa, int salen, char *addrbuf, int addrbuflen);

int              ReverseLookup(SOCKADDR *sa, int salen, char *namebuf, int namebuflen);

struct addrinfo *ResolveAddress(char *addr, char *port, int af, int type, int proto);

 

#ifdef _cplusplus

}

#endif

#endif

 

Add the resolve.h header definition file, resolve.cpp.

 

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

Using IP Header Include Option Program Examples: Adding the resolve.cpp definition file to the project

 

Add the source code.

 

// Common routines for resolving addresses and hostnames

// Files:

//      resolve.cpp     - Common routines

//      resolve.h       - Header file for common routines

// Description:

//      This file contains common name resolution and name printing

//      routines and is used by many of the samples on this CD.

//

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

#include <stdlib.h>

#include "resolve.h"

 

// Function: PrintAddress

// Description:

//    This routine takes a SOCKADDR structure and its length and prints

//    converts it to a string representation. This string is printed to the console via stdout.

int PrintAddress(SOCKADDR *sa, int salen)

{

    char    host[NI_MAXHOST], serv[NI_MAXSERV];

    int     hostlen = NI_MAXHOST, servlen = NI_MAXSERV, rc;

 

    rc = getnameinfo(sa, salen, host, hostlen, serv, servlen, NI_NUMERICHOST | NI_NUMERICSERV);

    if (rc != 0)

    {

        fprintf(stderr, "%s: getnameinfo() failed with error code %d\n", __FILE__, rc);

        return rc;

    }

    else

        printf("PrintAddress(): getnameinfo() is OK!\n");

 

    // If the port is zero then don't print it

    if (strcmp(serv, "0") != 0)

    {

        if (sa->sa_family == AF_INET)

            printf("[%s]:%s", host, serv);

        else

            printf("%s:%s", host, serv);

    }

    else

        printf("%s", host);

 

    return NO_ERROR;

}

 

// Function: FormatAddress

// Description:

//    This is similar to the PrintAddress function except that instead of

//    printing the string address to the console, it is formatted into the supplied string buffer.

int FormatAddress(SOCKADDR *sa, int salen, char *addrbuf, int addrbuflen)

{

    char    host[NI_MAXHOST], serv[NI_MAXSERV];

    int     hostlen = NI_MAXHOST, servlen = NI_MAXSERV, rc;

 

    rc = getnameinfo(sa, salen, host, hostlen, serv, servlen, NI_NUMERICHOST | NI_NUMERICSERV);

    if (rc != 0)

    {

        fprintf(stderr, "%s: getnameinfo() failed with error code %d\n", __FILE__, rc);

        return rc;

    }

    else

        printf("FormatAddress(): getnameinfo() is OK!\n");

 

    if ( (strlen(host) + strlen(serv) + 1) > (unsigned)addrbuflen)

        return WSAEFAULT;

    if (sa->sa_family == AF_INET)

        sprintf_s(addrbuf, sizeof(addrbuf), "%s:%s", host, serv);

    else if (sa->sa_family == AF_INET6)

        sprintf_s(addrbuf, sizeof(addrbuf), "[%s]:%s", host, serv);

    else

        addrbuf[0] = '\0';

 

    return NO_ERROR;

}

 

// Function: ResolveAddress

// Description:

//    This routine resolves the specified address and returns a list of addrinfo

//    structure containing SOCKADDR structures representing the resolved addresses.

//    Note that if 'addr' is non-NULL, then getaddrinfo will resolve it whether

//    it is a string literal address or a hostname.

struct addrinfo *ResolveAddress(char *addr, char *port, int af, int type, int proto)

{

    struct addrinfo hints,

    *res = NULL;

    int             rc;

 

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

    hints.ai_flags  = ((addr) ? 0 : AI_PASSIVE);

    hints.ai_family = af;

    hints.ai_socktype = type;

    hints.ai_protocol = proto;

 

    rc = getaddrinfo(addr, port, &hints, &res);

    if (rc != 0)

    {

        printf("Invalid address %s, getaddrinfo() failed with error code %d\n", addr, rc);

        return NULL;

    }

    else

        printf("ResolveAddress(): getnameinfo() is OK!\n");

 

    return res;

}

 

// Function: ReverseLookup

// Description:

//    This routine takes a SOCKADDR and does a reverse lookup for the name

//    corresponding to that address.

int ReverseLookup(SOCKADDR *sa, int salen, char *buf, int buflen)

{

    char    host[NI_MAXHOST];

    int     hostlen=NI_MAXHOST, rc;

 

    rc = getnameinfo(sa, salen, host, hostlen, NULL, 0, 0);

    if (rc != 0)

    {

        fprintf(stderr, "getnameinfo() failed with error code %d\n", rc);

        return rc;

    }

    else

        printf("ReverseLookup(): getnameinfo() is OK!\n");

    strcpy_s(buf, sizeof(host), host);

    return NO_ERROR;

}

 

Build and run the project.

 

Using IP Header Include Option Program Examples: A sample output with arguments

 

 

 

 

As we mentioned previously, using the header include option for IPv4 is easy because the stack will perform any fragmentation necessary. However, for IPv6 the stack will not, which means if your application needs to send raw data with a payload that exceeds the MTU, it will have to fragment the packets manually before sending them. This is accomplished by including the IPv6 fragmentation header after the IPv6 header but before the remaining payload. To do this, the IPv6 header's next header value will indicate the IPv6 fragmentation header (whose value is 44). The next header value of the IPv6 fragmentation header will then indicate IPPROTO_UDP. Also note that the UDP header occurs only once. The first fragment will contain the IPv6 header, IPv6 fragmentation header, UDP header, and as much of the payload that will fit into the MTU. The subsequent fragments will contain only the IPv6 header, the IPv6 fragmentation header, and the remaining payload. Figure 11-6 illustrates this example. In this case, the MTU is 1500 bytes but a 2000 byte payload is being sent.

 

Using IP Header Include Option Program Examples: The IPv6 UDP packet with fragmentation

 

Figure 11-6 IPv6 UDP packet with fragmentation

 

There are two routines of interest: PacketizeIpv4 and PacketizeIpv6. The v4 routine doesn't do anything of interest because we know the stack will fragment the data if required. However, the v6 routine will build the appropriate IPv6 header and fragmentation header for each fragment necessary.

 

 

 


< UDP RAW Socket Example | RAW Socket Main | Chap 12: Remote Access Service (RAS) >