< UDP RAW Socket Example | RAW Socket Main | Chap 12: Remote Access Service (RAS) >
What do we have in this chapter 11 part 6?
|
Add 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.
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.
-------------------------------------------------------
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.
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.
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) >