?? windows internet programming part 3.html
字號:
5.0 BUILDING HEADERS IN CODE
=======================================
The Headers are built using normal C structures, we declare a struct
for each header we want to build and declare a variable for each field
of the Header that we will be using.
While creating the structure we must remember that there are certain
expectations and limitations on the size of Headers, an IP Header is
20 Bytes in size, so we will have to use certain types of variables
to reflect the sizes of these fields the different variable types and
there sizes are as follows:
unsigned char = 1 byte (8 bits)
unsigned short int = 2 bytes (16 bits)
unsigned int = 4 bytes (32 bits)
5.1 THE IP HEADER
=======================================
The IP Header as explained above will be built using a structure
containing all of the fields in the IP Header. As you will remember
there are 14 fields in the IP Header, however we will not be using
any of the IP's Options or the padding, also in our examples we will
only be using single Datagrams so there will be no need for fragmenting
the packets so we will not be using the flags field and we will just
set the Fragment Offset to 0.
So with a total of 14 fields in the IP Header we will not be using 3
of them so that leaves us with 11 fields, also we will be storing the
Ip version and length in one variable so that means we will be using
a total of 10 variables for our code when building the Header.
Well here is the structure we will be using to build the IP Header:
typedef struct ip_hdr
{
unsigned char ip_verlen; // version & IHL => 1 Bytes (combined size of both)
unsigned char ip_tos; // TOS => 1 Bytes
unsigned short ip_totallength; // Total length => 2 Bytes
unsigned short ip_id; // Identification => 2 Bytes
unsigned short ip_offset; // Fragment Offset => 2 Bytes
unsigned char ip_ttl; // Time to live => 1 Bytes
unsigned char ip_protocol; // Protocol => 1 Bytes
unsigned short ip_checksum; // Header checksum => 2 Bytes
unsigned int ip_srcaddr; // Source address => 4 Bytes
unsigned int ip_destaddr; // Destination address => + 4 Bytes
// = 20 Bytes
}IP_HDR;
This structure contains all of the fields we will be using and the sizes
of the variables add up to 20 Bytes, the correct size of an IP Header,
note however that the Fragment Offset field is given a value of 2 Bytes
which is equal to 16 bits, the true size of the frag offset is 13 but we
altered it here to make up for the missing 3 bits of the flag field but
it wont make any difference to the packet this is still a perfectly formed
IP Header.
5.2 THE TCP HEADER
=======================================
With the below structure you will again notice that there are a few
of the TCP Headers fields missing, again Options and Padding are not
included as we will not be using them, that leaves us with a total of
10 fields and the reserved field has been left out because it is not
currently implemented by TCP so we are left with 9 fields to fill.
With the missing fields of the Header we have increased the sizes of
the Control Bits and Data Offset fields both to 1 Byte to make up the
20 Byte size of the TCP Header.
So here is the TCP Structure:
typedef struct tcp_hdr
{
unsigned short sport; // Source Port => 2 Bytes
unsigned short dport; // Destination Port => 2 Bytes
unsigned int seqnum; // Sequence Number => 4 Bytes
unsigned int acknum; // Acknowledgement Number => 4 Bytes
unsigned char DataOffset; // Data Offset => 1 Bytes
unsigned char Flags; // Control Bits => 1 Bytes
unsigned short Windows; // Window => 2 Bytes
unsigned short Checksum; // Checksum => 2 Bytes
unsigned short UrgPointer; // Urgent Pointer => + 2 Bytes
// = 20 Bytes
}TCP_HDR;
5.3 THE UDP HEADER
=======================================
The below structure is the UDP Header, unlike previous headers it is
not missing any fields and adds up to a totalsize of 8 Bytes.
typedef struct udp_hdr
{
unsigned short sport; // Source Port => 2 Bytes
unsigned short dport; // Destination Port => 2 Bytes
unsigned short Length; // Length => 2 Bytes
unsigned short Checksum; // Checksum => + 2 Bytes
// = 8 Bytes
}UDP_HDR;
5.4 THE ICMP HEADER
=======================================
The ICMP Header is similiar to the UDP Header, it has very few fields
and it adds up to a size of 8 Bytes.
typedef struct tagICMPHDR
{
unsigned char icmp_type; // Type of message => 1 Bytes
unsigned char icmp_code; // Type sub code => 1 Bytes
unsigned short icmp_cksum; // Checksum => 2 Bytes
unsigned short icmp_id; // Identifer => 2 Bytes
unsigned short icmp_seq; // sequence number => + 2 Bytes
// = 8 Bytes
} ICMPHDR, *PICMPHDR;
5.5 THE PSUEDO HEADER
=======================================
The Psuedo Header is used to protect against misrouted segments,
its size is 12 Bytes, the following structure forms the Psuedo
Header:
typedef struct ps_hdr
{
unsigned int source_address; // Source Address => 4 Bytes
unsigned int dest_address; // Destination Address => 4 Bytes
unsigned char placeholder; // Place Holder => 1 Bytes
unsigned char protocol; // Protocol => 1 Bytes
unsigned short tcp_length; // TCP Length => + 2 Bytes
// = 12 Bytes
struct tcp_hdr tcp;
}PS_HDR;
5.6 THE CHECKSUM FUNCTION
=======================================
The Checksum Function is needed to calculate the size of the
packet, here is the functions code:
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);
}
6.0 SOURCE CODE
=======================================
Well in the Source Code we are first going to look at code which is
supported by all Winsock 2 Systems including Win 9x ones so that
every-1 can av' a go as it were. So in this section we are going to
put what weve learned so far together and create a working internet
application by using the icmp protocol to send an ICMP Echo Request
message, the first part of a ping program. First tough we are going
to create a header ".h" file for the application, the file contains
the checksum function and structures for the IP and ICMP headers.
Remember you will have to make sure that the header file is included
correctly with the source file and that you linked to Ws2_32.lib.
6.1 ICMP ECHO REQUEST
=======================================
/********************* icmp.h header file ************************/
// ICMP message types
#define ICMP_ECHOREQ 13 // Echo request query
// IP Header
typedef struct ip_hdr
{
unsigned char ip_verlen; // version & IHL => 1 Bytes (combined size of both)
unsigned char ip_tos; // TOS => 1 Bytes
unsigned short ip_totallength; // Total length => 2 Bytes
unsigned short ip_id; // Identification => 2 Bytes
unsigned short ip_offset; // Fragment Offset => 2 Bytes
unsigned char ip_ttl; // Time to live => 1 Bytes
unsigned char ip_protocol; // Protocol => 1 Bytes
unsigned short ip_checksum; // Header checksum => 2 Bytes
unsigned int ip_srcaddr; // Source address => 4 Bytes
unsigned int ip_destaddr; // Destination address => + 4 Bytes
// = 20 Bytes
}IP_HDR;
// ICMP Header
typedef struct tagICMPHDR
{
unsigned char icmp_type; // Type of message => 1 Bytes
unsigned char icmp_code; // Type sub code => 1 Bytes
unsigned short icmp_cksum; // Checksum => 2 Bytes
unsigned short icmp_id; // Identifer => 2 Bytes
unsigned short icmp_seq; // sequence number => + 2 Bytes
// = 8 Bytes
} ICMPHDR, *PICMPHDR;
#define REQ_DATASIZE 32 // Echo Request Data size
// ICMP Echo Request
typedef struct tagECHOREQUEST
{
ICMPHDR icmpHdr;
char cData[REQ_DATASIZE];
} ECHOREQUEST, *PECHOREQUEST;
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);
}
/********************* icmp.h header file ************************/
So in the header file we first #defined some code type for ICMP
Echo Request to make things a bit more readable later on, then we
set up our IP and ICMP structures by giving variables for each field
in the Protocol headers. Notice the sizes of each field add up
correctly for the sizes of the protocol headers, we also have a
structure called ECHOREQUEST, all icmp messages have different
fields except for the common ones defined in the icmp header above,
the fields of ECHOREQUEST are the extra fields nedded for echo's.
We then have a function to calculate the checksum, all these bits
of code are just placed inside our .h file to keep things shorter
and more readable in the main program, speaking of which...
/********************* icmp.c source file ************************/
// Make sure you always include your headers and link your libraries :)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include "icmp.h"
void main(int argc, char **argv)
{
DWORD dip = inet_addr(argv[1]);
WSADATA wsaData;
SOCKET sock;
static ECHOREQUEST echo_req;
struct sockaddr_in sin;
// Startup WinSock
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("WSAStartup failure!");
}
// Create a raw socket
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == SOCKET_ERROR)
{
printf("Error starting socket");
}
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = dip;
// Fill in echo request
echo_req.icmpHdr.icmp_type = ICMP_ECHOREQ;
echo_req.icmpHdr.icmp_code = 0;
echo_req.icmpHdr.icmp_cksum = 0;
echo_req.icmpHdr.icmp_id = 1;
echo_req.icmpHdr.icmp_seq = 1;
// Fill in some data to send
memset(echo_req.cData, ' ', REQ_DATASIZE);
// Compute checksum
echo_req.icmpHdr.icmp_cksum = checksum((unsigned short *)&echo_req, sizeof(ECHOREQUEST));
// Status mesage
printf("Sending Echo Request to <%s>.\n", argv[1]);
// Send the echo request
if (sendto(sock, (const char *) &echo_req, sizeof(ECHOREQUEST), 0, (SOCKADDR *) dip, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
printf("sendto() failed: %d\n", WSAGetLastError());
return -1;
}
// Status mesage
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -