📄 rawudp.cpp
字号:
//
// Sample: Raw IPv4/IPv6 UDP with IP_HDRINCL option
//
// Files:
// rawudp.cpp - this file
// iphdr.h - IPv4, IPv6, and UDP 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.
//
// Compile:
// cl -o rawudp.exe rawudp.cpp resolve.cpp ws2_32.lib
//
// Usage:
// rawudp.exe [options]
// -a 4|6 Address family
// -sa addr From (sender) port number
// -sp int From (sender) IP address
// -da addr To (recipient) port number
// -dp int To (recipient) IP address
// -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
#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" // 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.
//
void 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) port number\n"
" -sp int From (sender) IP address\n"
" -da addr To (recipient) port number\n"
" -dp int To (recipient) IP address\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
);
ExitProcess(1);
}
//
// 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]))
{
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)
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)
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 thats 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -