winpcap实现从TCP三次握手到发送http请求

之前的文章我都是贴出了协议的格式,对具体字段没有具体说明,今天在这里补充一下。

/*                       IP报文格式
0            8           16                        32
+------------+------------+-------------------------+
| ver + hlen |  服务类型  |         总长度          |
+------------+------------+----+--------------------+
|           标识位        |flag|   分片偏移(13位)   |
+------------+------------+----+--------------------+
|  生存时间  | 高层协议号 |       首部校验和        |
+------------+------------+-------------------------+
|                   源 IP 地址                      |
+---------------------------------------------------+
|                  目的 IP 地址                     |
+---------------------------------------------------+
*/

版本号(Version)字段标明了IP 协议的版本号,目前的协议版本号为4,下一代IP 协议的版本号为6,占4位。

普通的 IP 头部长度为20 个字节,不包含IP 选项字段,注意:这里的头部长度是以4字节即32位为单位的,所以真正的IP报头长度应该是该值 * 4。占4位

位的服务类型(TOS,Type of Service)字段包括一个3 位的优先权字段(COS,Class of Service),4 位TOS 字段和1 位未用位。4 位TOS 分别代表最小时延、最大吞吐量、最高可靠性和最小费用。一般是置0的。

总长度(Total length)是整个IP 数据报长度,如果上层是TCP协议,则总长度 = IP报头长度 + TCP报头长度 + 数据长度。

标识符(Identification)字段唯一地标识主机发送的每一份数据报。通常每发送一份报文它的值就会加1,我试验的时候没有加一,服务器也能响应。

生存时间(TTL,Time to Live)字段设置了数据包可以经过的路由器数目。一旦经过一个路由器,TTL 值就会减1,当该字段值为0 时,数据包将被丢弃,所以你可以将该置设成最大0xFF。

高层协议号:IP是网络层协议,要为传输层服务,一般来说高层协议有TCP、UDP,还可以是ICMP,因为ICMP也是用IP包发送的。TCP 为6,UDP为17,ICMP为1。

首部校验和(Head checksum):IP 头部的校验和,如果有选项字段,那就要一起校验,在计算校验和时一定先要将其值为0。

最后两项是源主机ip地址和目标主机ip地址。


/*
                     TCP 报文
0                       16                       32	
+------------------------+-------------------------+
|      源端口地址        |      目的端口地址       |
+------------------------+-------------------------+
|                      序列号                      |
+--------------------------------------------------+
|                      确认号                      |
+------+--------+--------+-------------------------+
|HLEN/4| 保留位 |控制位/6|         窗口尺寸        |
+------+--------+--------+-------------------------+
|         校验和         |         应急指针        |
+------------------------+-------------------------+
*/

源端口号:标识主机上发起传送的应用程序;

目的端口:标识主机上传送要到达的应用程序。

顺序号:用来标识从TCP源端向TCP目标端发送的数据字节流,它表示在这个报文段中的第一个数据字节。

确认号:只有ACK标志为1时,确认号字段才有效。它包含目标端所期望收到源端的下一个数据字节。

头部长度:TCP报头的长度,单位是4字节即32位,如果没有选项字段,则TCP报头为20字节,这个地方写20 / 4 = 5。这个字段也叫数据偏移量,表示数据开始的地方。

预留:由跟在数据偏移字段后的6位构成,预留位通常为0。

标志位:(U、A、P、R、S、F):占6位。从左到右依次是URG、ACK、PSH、RST、SYN、FIN。各位的含义如下:
  URG:紧急指针(urgent pointer)有效。
  ACK:确认序号有效。
  PSH:接收方应该尽快将这个报文段交给应用层。
  RST:重建连接。
  SYN:发起一个连接。
  FIN:释放一个连接。
窗口大小:占16比特。此字段用来进行流量控制。单位为字节数,这个值是本机期望一次接收的字节数。

TCP校验和:TCP报头校验和。注意,这个地方要校验的不仅仅是TCP报头数据,而是伪报头 + TCP报头 + TCP数据 这三个数据,很多人在这个地方少了。

紧急指针字段:占16比特。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。


TCP伪报头

struct PSDTCP_HEADER
{ 
	byte srcIpAddr[4];     //Source IP address; 32 bits
	byte dstIpAddr[4];     //Destination IP address; 32 bits 
	byte padding;          //padding
	byte protocol;         //Protocol; 8 bits
	byte tcpLen[2];        //TCP length; 16 bits
} ;

上面说了,在计算TCP校验和时需要伪报头,主要是要用源 /目的主机的IP地址和运输层网络协议号。其实按照协议分层来说,TCP所在的传输层应该和IP地址所在的网络层是分开的,现在传输层要访问网络层报文中的IP地址,好像违反了规定。


最后就是以太网头了如下:

struct ETHERNET_HEADER
{  
	byte dstMacAddr[6];
	byte srcMacAddr[6];
	byte ethernetType[2];
};
以太网头主要是源主机和目标主机的mac地址以及协议,比如IP或者ARP, 这个地方再强调一点,我们很容易获取源主机的mac地址,但对目标主机就不一定了,假如只是做试验,我们可能知道,但假如我们真的要给外网服务器发送,那就不行了,我们不可能知道百度服务器的mac地址,所以在给外网发送时,目标主机的mac地址应该写网关的mac地址,直接发给网关。网上很多帖子在这个地方说的都很模糊,有些甚至是直接全写0xFF。


我们闭着眼可以画出TCP三次握手的连接图,但是你有没有想过,当经过三次握手建立连接后,数据时怎么传递的,在传递数据的时候那几个标志位是什么,是SYN还是ACK,这个网上资料很少,我是先抓包研究的,最后结果如下:


winpcap实现从TCP三次握手到发送http请求


经抓包分析得知,最后发送数据时发的是ack和psh包,至于为什么是ack和psh,我现在还不知道,等接下来慢慢研究。

我连的是百度的服务器,怎么获取百度服务器的ip地址,我别的文章中有,目的端口是80,源端口是随机的。


int main()
{
	srand(time(0));
	unsigned short srcPort = rand()%65535;//6382;
	const char *lpszSrcIp = "10.126.72.37";
	const char *lpszDstIp = "112.80.248.73";
	const byte srcMac[] = {0x90, 0x2B, 0x34, 0x9A, 0xC2, 0xBB};//主机mac
	const byte dstMac[] = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x48}; //网关mac

	char szError[1024];
	const char *lpszAdapterName = "\\Device\\NPF_{1DDB19E0-EC33-46E2-ACB5-085E87EF6489}";
	pcap_t *handle = pcap_open_live(lpszAdapterName, 65536, 1, 1000, szError );
	if ( NULL == handle ) return 0;

	TCP_HEADER tcpHeader;
	memset(&tcpHeader, 0, sizeof tcpHeader );
	*(unsigned short *)tcpHeader.srcPort = htons(srcPort);
	*(unsigned short *)tcpHeader.dstPort = htons(80);
	*(unsigned int *)tcpHeader.seqNumber = htonl(0x00);
	*(unsigned int *)tcpHeader.ackNumber = htonl(0x00);
	tcpHeader.headLen = 5 << 4; 
	tcpHeader.contrl = 1 << 1;
	*(unsigned short *)tcpHeader.wndSize = htons(0xFFFF);

	PSDTCP_HEADER psdHeader;
	memset(&psdHeader, 0, sizeof psdHeader);
	*(unsigned int *)psdHeader.dstIpAddr = inet_addr(lpszSrcIp);
	*(unsigned int *)psdHeader.srcIpAddr = inet_addr(lpszDstIp);
	psdHeader.protocol = 0x06;
	*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER));

	byte psdPacket[1024];
	memset(psdPacket, 0, sizeof psdPacket);
	memcpy( psdPacket, &psdHeader, sizeof psdHeader );
	memcpy( psdPacket + sizeof psdHeader, &tcpHeader, sizeof tcpHeader );

	*(unsigned short *)tcpHeader.checkSum = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof tcpHeader );
	
	IP_HEADER ipHeader;
	memset( &ipHeader, 0, sizeof ipHeader );
	unsigned char versionAndLen = 0x04;
	versionAndLen <<= 4;
	versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度

	ipHeader.versionAndHeader = versionAndLen;
	*(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + sizeof(TCP_HEADER) ); 

	ipHeader.ttl = 0xFF;
	ipHeader.hiProtovolType = 0x06;

	*(unsigned int *)(ipHeader.srcIpAddr) = inet_addr(lpszSrcIp);
	*(unsigned int *)(ipHeader.dstIpAddr) = inet_addr(lpszDstIp);
	*(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );

	ETHERNET_HEADER ethHeader;
	memset(ðHeader, 0, sizeof ethHeader);
	memcpy(ethHeader.dstMacAddr, dstMac, 6);
	memcpy(ethHeader.srcMacAddr, srcMac, 6);
	*(unsigned short *)ethHeader.ethernetType = htons(0x0800);

	byte packet[1024];
	memset(packet, 0, sizeof packet);

	memcpy(packet, ðHeader, sizeof ethHeader);
	memcpy(packet + sizeof ethHeader, &ipHeader, sizeof ipHeader);
	memcpy(packet + sizeof ethHeader + sizeof ipHeader, &tcpHeader, sizeof tcpHeader);
	
	int size = sizeof ethHeader + sizeof ipHeader + sizeof tcpHeader;
	pcap_sendpacket(handle, packet, size );
	printf("%-16s ------SYN-----> %-16s\n", lpszSrcIp, lpszDstIp );

	if ( NULL == handle )
	{
		printf("\nUnable to open the adapter. %s is not supported by WinPcap\n");
		return 0;
	}
	byte param[1024];
	memset(param, 0x00, sizeof param );
	memcpy(param, &srcPort, sizeof srcPort );
	memcpy(param + sizeof srcPort, handle, 512 );
	pcap_loop( handle, -1, HandlePacketCallBack, param );
	pcap_close(handle);	
	return 0;
}

main函数先发起连接请求,即就是三次握手的第一步,然后开始抓包,如果抓到服务器回过来的SYN + ACK包,就表明服务器完成了第二次握手,接着向服务器再次发送ACK即就是第三次握手数据包,这样便建立了连接,然后可以向服务器发送HTTP请求,等待服务器回应。将适配器句柄和本地端口作为参数传给回调函数,用来发包和过滤。

void HandlePacketCallBack(unsigned char *param,const struct pcap_pkthdr* packet_header, const unsigned char *recvPacket)
{
	unsigned short localPort = *(unsigned short *)param;

	ETHERNET_HEADER *pEthHeader = ( ETHERNET_HEADER *)recvPacket;
	if ( *((unsigned short *)(pEthHeader->ethernetType)) != htons(0x0800) ) return;

	IP_HEADER *pIpHeader = ( IP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) );
	if ( pIpHeader->hiProtovolType != 0x06 ) return;

	TCP_HEADER *pTcpHeader = ( TCP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER) );
	if ( *(unsigned short *)(pTcpHeader->dstPort) != htons(localPort) ) return ;

	//////////////////////////////////////////////////////////////////////
	IP_HEADER ipHeader;
	memset( &ipHeader, 0, sizeof ipHeader );
	unsigned char versionAndLen = 0x04;
	versionAndLen <<= 4;
	versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度

	ipHeader.versionAndHeader = versionAndLen;
	*(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + sizeof(TCP_HEADER) ); 

	ipHeader.ttl = 0xFF;
	ipHeader.hiProtovolType = 0x06;

	memcpy(ipHeader.srcIpAddr, pIpHeader->dstIpAddr, sizeof(unsigned int) );
	memcpy(ipHeader.dstIpAddr, pIpHeader->srcIpAddr, sizeof(unsigned int) );

	*(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );

	////////////////////////////////////////////////////////////////////
	unsigned int ack = ntohl(*(unsigned int *)(pTcpHeader->seqNumber));
	unsigned int seq =  ntohl(*(unsigned int *)(pTcpHeader->ackNumber));

	TCP_HEADER tcpHeader;
	memset(&tcpHeader, 0, sizeof tcpHeader );
	*(unsigned short *)tcpHeader.srcPort = htons(localPort);
	*(unsigned short *)tcpHeader.dstPort = htons(80);
	*(unsigned int *)tcpHeader.seqNumber = htonl(seq);
	*(unsigned int *)tcpHeader.ackNumber = htonl(ack + 1);
	tcpHeader.headLen = 5 << 4; 
	tcpHeader.contrl = 0x01 << 4; //
	*(unsigned short *)tcpHeader.wndSize = htons(0xFFFF);

	///////////////////////////////////////////////////////////////////
	PSDTCP_HEADER psdHeader;
	memset(&psdHeader, 0x00, sizeof psdHeader);
	psdHeader.protocol = 0x06;
	*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER));
	memcpy(psdHeader.dstIpAddr, ipHeader.dstIpAddr, sizeof(unsigned int) );
	memcpy(psdHeader.srcIpAddr, ipHeader.srcIpAddr, sizeof(unsigned int) );

	byte psdPacket[1024];
	memcpy( psdPacket, &psdHeader, sizeof psdHeader );
	memcpy( psdPacket + sizeof psdHeader, &tcpHeader, sizeof tcpHeader );

	*(unsigned short *)tcpHeader.checkSum = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof tcpHeader );

	ETHERNET_HEADER ethHeader;
	memset(ðHeader, 0, sizeof ethHeader);
	memcpy(ethHeader.dstMacAddr, pEthHeader->srcMacAddr, 6);
	memcpy(ethHeader.srcMacAddr, pEthHeader->dstMacAddr, 6);
	*(unsigned short *)ethHeader.ethernetType = htons(0x0800);

	byte packet[1024];
	memset(packet, 0, sizeof packet);

	memcpy(packet, ðHeader, sizeof ethHeader);
	memcpy(packet + sizeof ethHeader, &ipHeader, sizeof ipHeader);
	memcpy(packet + sizeof ethHeader + sizeof ipHeader, &tcpHeader, sizeof tcpHeader);

	int size = sizeof ethHeader + sizeof ipHeader + sizeof tcpHeader;

	pcap_t *handle = (pcap_t*)(param + sizeof(unsigned short));

	byte data[] = "GET / HTTP/1.1\r\n\r\n";

	char srcIp[32], dstIp[32];
	byte ctrl = pTcpHeader->contrl & 0x3F;
	switch ( ctrl )
	{
	case 0x01 << 1: //syn
		break;
	/*case 0x01 << 4: //ack
		puts("收到ack");
		break;*/
	case ((0x01 << 4) | (0x01 << 1)): //syn+ack

		FormatIpAddr(*(unsigned int *)(pIpHeader->srcIpAddr), srcIp );
		FormatIpAddr(*(unsigned int *)(pIpHeader->dstIpAddr), dstIp );
		printf("%-16s ---SYN + ACK--> %-16s\n", srcIp, dstIp );

		///////////////////////////////////////////////////////////

		pcap_sendpacket(handle, packet, size );
		FormatIpAddr(*(unsigned int *)ipHeader.srcIpAddr, srcIp );
		FormatIpAddr(*(unsigned int *)ipHeader.dstIpAddr, dstIp );
		printf("%-16s ------ACK-----> %-16s\n", srcIp, dstIp );

		Sleep(10);

		pIpHeader = (IP_HEADER *)(packet + sizeof(ETHERNET_HEADER) );
		*(unsigned short *)(pIpHeader->totalLen) = htons(sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof data );
		memset(pIpHeader->headerCheckSum, 0x00, sizeof(unsigned short) );
		*(unsigned short *)(pIpHeader->headerCheckSum) = CheckSum( (unsigned short *)pIpHeader, sizeof(IP_HEADER) );

		pTcpHeader = (TCP_HEADER *)(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER));
		pTcpHeader->contrl = 0x01 << 4;
		*(unsigned int *)(pTcpHeader->ackNumber) = htonl(ack+1);
		*(unsigned int *)(pTcpHeader->seqNumber) = htonl(seq);
		memset( pTcpHeader->checkSum, 0x00, sizeof(unsigned short) );

		memset( psdPacket, 0x00, sizeof psdPacket );
		*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER) + sizeof(data));

		memcpy( psdPacket, &psdHeader, sizeof psdHeader );
		memcpy( psdPacket + sizeof psdHeader, pTcpHeader, sizeof(TCP_HEADER) );
		memcpy( psdPacket + sizeof psdHeader + sizeof(TCP_HEADER), data, sizeof data );

		*(unsigned short *)(pTcpHeader->checkSum) = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof(TCP_HEADER) + sizeof data );

		memcpy(packet, ðHeader, sizeof ethHeader);
		memcpy(packet + sizeof(ETHERNET_HEADER), pIpHeader, sizeof(IP_HEADER) );
		memcpy(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER), pTcpHeader, sizeof(TCP_HEADER) );
		memcpy(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER)+ sizeof(TCP_HEADER), data, sizeof data );
		
		size += sizeof data;
		pcap_sendpacket(handle, packet, size );
		
		break;		
	default:
		IP_HEADER *pIpHeader = (IP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) );
		unsigned short ipHeaderLen = pIpHeader->versionAndHeader & 0x0F;
		ipHeaderLen *= 4;
		TCP_HEADER *pTcpHeader = (TCP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER)  + ipHeaderLen );

		int tcpHeaderLen = pTcpHeader->headLen >> 0x04;
		tcpHeaderLen *= 4;
		char *str = ( char *)(recvPacket + sizeof(ETHERNET_HEADER) + ipHeaderLen + tcpHeaderLen );
		puts(str);
	}
	return;
}

回调函数首先过滤掉非IP数据包,再过滤掉非TCP数据包,再根据端口过滤掉不是自己的TCP数据包。值得注意的就是组包时的包长度和校验和,我就在这个地方耗了很久。

在解析包的时候最好不要直接用sizeof(IP_HEADER)这样类似的写法,而是直接读取报头中的报头长度字段,这样会更精确些,因为我们不用知道服务器有没有添加选项数据。

最后的结果:

winpcap实现从TCP三次握手到发送http请求


最后贴上全部源码

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <winsock2.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "../common/lib/Packet.lib")
#pragma comment(lib, "../common/lib/wpcap.lib")
#pragma comment(lib, "ws2_32.lib")


/*                       IP报文格式
0            8           16                        32
+------------+------------+-------------------------+
| ver + hlen |  服务类型  |         总长度          |
+------------+------------+----+--------------------+
|           标识位        |flag|   分片偏移(13位)   |
+------------+------------+----+--------------------+
|  生存时间  | 高层协议号 |       首部校验和        |
+------------+------------+-------------------------+
|                   源 IP 地址                      |
+---------------------------------------------------+
|                  目的 IP 地址                     |
+---------------------------------------------------+
*/

struct IP_HEADER
{
	byte versionAndHeader;
	byte serviceType;
	byte totalLen[2];
	byte seqNumber[2];
	byte flagAndFragPart[2];
	byte ttl;
	byte hiProtovolType;
	byte headerCheckSum[2];
	byte srcIpAddr[4];
	byte dstIpAddr[4];
};

/*
                     TCP 报文
0                       16                       32	
+------------------------+-------------------------+
|      源端口地址        |      目的端口地址       |
+------------------------+-------------------------+
|                      序列号                      |
+--------------------------------------------------+
|                      确认号                      |
+------+--------+--------+-------------------------+
|HLEN/4| 保留位 |控制位/6|         窗口尺寸        |
+------+--------+--------+-------------------------+
|         校验和         |         应急指针        |
+------------------------+-------------------------+
*/

struct TCP_HEADER
{
	byte srcPort[2];
	byte dstPort[2];
	byte seqNumber[4];
	byte ackNumber[4];
	byte headLen;
	byte contrl;
	byte wndSize[2];
	byte checkSum[2];
	byte uragentPtr[2];
};

struct PSDTCP_HEADER
{ 
	byte srcIpAddr[4];     //Source IP address; 32 bits
	byte dstIpAddr[4];     //Destination IP address; 32 bits 
	byte padding;          //padding
	byte protocol;         //Protocol; 8 bits
	byte tcpLen[2];        //TCP length; 16 bits
} ;

struct ETHERNET_HEADER
{  
	byte dstMacAddr[6];
	byte srcMacAddr[6];
	byte ethernetType[2];
};


char *FormatIpAddr( unsigned uIpAddr, char szIp[] )
{
	IN_ADDR addr;
	addr.S_un.S_addr = uIpAddr;

	strcpy( szIp, inet_ntoa( addr ) );
	return szIp;
}

unsigned short CheckSum(unsigned short packet[], int size )
{
	unsigned long cksum = 0;
	while (size > 1) 
	{
		cksum += *packet++;
		size -= sizeof(USHORT);
	}
	if (size) 
	{
		cksum += *(UCHAR*)packet;
	}
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >>16);

	return (USHORT)(~cksum);
}

void HandlePacketCallBack(unsigned char *param,const struct pcap_pkthdr* packet_header, const unsigned char *recvPacket)
{
	unsigned short localPort = *(unsigned short *)param;

	ETHERNET_HEADER *pEthHeader = ( ETHERNET_HEADER *)recvPacket;
	if ( *((unsigned short *)(pEthHeader->ethernetType)) != htons(0x0800) ) return;

	IP_HEADER *pIpHeader = ( IP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) );
	if ( pIpHeader->hiProtovolType != 0x06 ) return;

	TCP_HEADER *pTcpHeader = ( TCP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER) );
	if ( *(unsigned short *)(pTcpHeader->dstPort) != htons(localPort) ) return ;

	//////////////////////////////////////////////////////////////////////
	IP_HEADER ipHeader;
	memset( &ipHeader, 0, sizeof ipHeader );
	unsigned char versionAndLen = 0x04;
	versionAndLen <<= 4;
	versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度

	ipHeader.versionAndHeader = versionAndLen;
	*(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + sizeof(TCP_HEADER) ); 

	ipHeader.ttl = 0xFF;
	ipHeader.hiProtovolType = 0x06;

	memcpy(ipHeader.srcIpAddr, pIpHeader->dstIpAddr, sizeof(unsigned int) );
	memcpy(ipHeader.dstIpAddr, pIpHeader->srcIpAddr, sizeof(unsigned int) );

	*(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );

	////////////////////////////////////////////////////////////////////
	unsigned int ack = ntohl(*(unsigned int *)(pTcpHeader->seqNumber));
	unsigned int seq =  ntohl(*(unsigned int *)(pTcpHeader->ackNumber));

	TCP_HEADER tcpHeader;
	memset(&tcpHeader, 0, sizeof tcpHeader );
	*(unsigned short *)tcpHeader.srcPort = htons(localPort);
	*(unsigned short *)tcpHeader.dstPort = htons(80);
	*(unsigned int *)tcpHeader.seqNumber = htonl(seq);
	*(unsigned int *)tcpHeader.ackNumber = htonl(ack + 1);
	tcpHeader.headLen = 5 << 4; 
	tcpHeader.contrl = 0x01 << 4; //
	*(unsigned short *)tcpHeader.wndSize = htons(0xFFFF);

	///////////////////////////////////////////////////////////////////
	PSDTCP_HEADER psdHeader;
	memset(&psdHeader, 0x00, sizeof psdHeader);
	psdHeader.protocol = 0x06;
	*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER));
	memcpy(psdHeader.dstIpAddr, ipHeader.dstIpAddr, sizeof(unsigned int) );
	memcpy(psdHeader.srcIpAddr, ipHeader.srcIpAddr, sizeof(unsigned int) );

	byte psdPacket[1024];
	memcpy( psdPacket, &psdHeader, sizeof psdHeader );
	memcpy( psdPacket + sizeof psdHeader, &tcpHeader, sizeof tcpHeader );

	*(unsigned short *)tcpHeader.checkSum = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof tcpHeader );

	ETHERNET_HEADER ethHeader;
	memset(ðHeader, 0, sizeof ethHeader);
	memcpy(ethHeader.dstMacAddr, pEthHeader->srcMacAddr, 6);
	memcpy(ethHeader.srcMacAddr, pEthHeader->dstMacAddr, 6);
	*(unsigned short *)ethHeader.ethernetType = htons(0x0800);

	byte packet[1024];
	memset(packet, 0, sizeof packet);

	memcpy(packet, ðHeader, sizeof ethHeader);
	memcpy(packet + sizeof ethHeader, &ipHeader, sizeof ipHeader);
	memcpy(packet + sizeof ethHeader + sizeof ipHeader, &tcpHeader, sizeof tcpHeader);

	int size = sizeof ethHeader + sizeof ipHeader + sizeof tcpHeader;

	pcap_t *handle = (pcap_t*)(param + sizeof(unsigned short));

	byte data[] = "GET / HTTP/1.1\r\n\r\n";

	char srcIp[32], dstIp[32];
	byte ctrl = pTcpHeader->contrl & 0x3F;
	switch ( ctrl )
	{
	case 0x01 << 1: //syn
		break;
	/*case 0x01 << 4: //ack
		puts("收到ack");
		break;*/
	case ((0x01 << 4) | (0x01 << 1)): //syn+ack

		FormatIpAddr(*(unsigned int *)(pIpHeader->srcIpAddr), srcIp );
		FormatIpAddr(*(unsigned int *)(pIpHeader->dstIpAddr), dstIp );
		printf("%-16s ---SYN + ACK--> %-16s\n", srcIp, dstIp );

		///////////////////////////////////////////////////////////

		pcap_sendpacket(handle, packet, size );
		FormatIpAddr(*(unsigned int *)ipHeader.srcIpAddr, srcIp );
		FormatIpAddr(*(unsigned int *)ipHeader.dstIpAddr, dstIp );
		printf("%-16s ------ACK-----> %-16s\n", srcIp, dstIp );

		Sleep(10);

		pIpHeader = (IP_HEADER *)(packet + sizeof(ETHERNET_HEADER) );
		*(unsigned short *)(pIpHeader->totalLen) = htons(sizeof(IP_HEADER) + sizeof(TCP_HEADER) + sizeof data );
		memset(pIpHeader->headerCheckSum, 0x00, sizeof(unsigned short) );
		*(unsigned short *)(pIpHeader->headerCheckSum) = CheckSum( (unsigned short *)pIpHeader, sizeof(IP_HEADER) );

		pTcpHeader = (TCP_HEADER *)(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER));
		pTcpHeader->contrl = 0x01 << 4;
		*(unsigned int *)(pTcpHeader->ackNumber) = htonl(ack+1);
		*(unsigned int *)(pTcpHeader->seqNumber) = htonl(seq);
		memset( pTcpHeader->checkSum, 0x00, sizeof(unsigned short) );

		memset( psdPacket, 0x00, sizeof psdPacket );
		*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER) + sizeof(data));

		memcpy( psdPacket, &psdHeader, sizeof psdHeader );
		memcpy( psdPacket + sizeof psdHeader, pTcpHeader, sizeof(TCP_HEADER) );
		memcpy( psdPacket + sizeof psdHeader + sizeof(TCP_HEADER), data, sizeof data );

		*(unsigned short *)(pTcpHeader->checkSum) = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof(TCP_HEADER) + sizeof data );

		memcpy(packet, ðHeader, sizeof ethHeader);
		memcpy(packet + sizeof(ETHERNET_HEADER), pIpHeader, sizeof(IP_HEADER) );
		memcpy(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER), pTcpHeader, sizeof(TCP_HEADER) );
		memcpy(packet + sizeof(ETHERNET_HEADER) + sizeof(IP_HEADER)+ sizeof(TCP_HEADER), data, sizeof data );
		
		size += sizeof data;
		pcap_sendpacket(handle, packet, size );
		
		break;		
	default:
		IP_HEADER *pIpHeader = (IP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER) );
		unsigned short ipHeaderLen = pIpHeader->versionAndHeader & 0x0F;
		ipHeaderLen *= 4;
		TCP_HEADER *pTcpHeader = (TCP_HEADER *)(recvPacket + sizeof(ETHERNET_HEADER)  + ipHeaderLen );

		int tcpHeaderLen = pTcpHeader->headLen >> 0x04;
		tcpHeaderLen *= 4;
		char *str = ( char *)(recvPacket + sizeof(ETHERNET_HEADER) + ipHeaderLen + tcpHeaderLen );
		puts(str);
	}
	return;
}

int main()
{
	srand(time(0));
	unsigned short srcPort = rand()%65535;//6382;
	const char *lpszSrcIp = "10.126.72.37";
	const char *lpszDstIp = "112.80.248.73";
	const byte srcMac[] = {0x90, 0x2B, 0x34, 0x9A, 0xC2, 0xBB};//主机mac
	const byte dstMac[] = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x48}; //网关mac

	char szError[1024];
	const char *lpszAdapterName = "\\Device\\NPF_{1DDB19E0-EC33-46E2-ACB5-085E87EF6489}";
	pcap_t *handle = pcap_open_live(lpszAdapterName, 65536, 1, 1000, szError );
	if ( NULL == handle ) return 0;

	TCP_HEADER tcpHeader;
	memset(&tcpHeader, 0, sizeof tcpHeader );
	*(unsigned short *)tcpHeader.srcPort = htons(srcPort);
	*(unsigned short *)tcpHeader.dstPort = htons(80);
	*(unsigned int *)tcpHeader.seqNumber = htonl(0x00);
	*(unsigned int *)tcpHeader.ackNumber = htonl(0x00);
	tcpHeader.headLen = 5 << 4; 
	tcpHeader.contrl = 1 << 1;
	*(unsigned short *)tcpHeader.wndSize = htons(0xFFFF);

	PSDTCP_HEADER psdHeader;
	memset(&psdHeader, 0, sizeof psdHeader);
	*(unsigned int *)psdHeader.dstIpAddr = inet_addr(lpszSrcIp);
	*(unsigned int *)psdHeader.srcIpAddr = inet_addr(lpszDstIp);
	psdHeader.protocol = 0x06;
	*(unsigned short *)psdHeader.tcpLen = htons(sizeof(TCP_HEADER));

	byte psdPacket[1024];
	memset(psdPacket, 0, sizeof psdPacket);
	memcpy( psdPacket, &psdHeader, sizeof psdHeader );
	memcpy( psdPacket + sizeof psdHeader, &tcpHeader, sizeof tcpHeader );

	*(unsigned short *)tcpHeader.checkSum = CheckSum( (unsigned short*) psdPacket, sizeof psdHeader + sizeof tcpHeader );
	
	IP_HEADER ipHeader;
	memset( &ipHeader, 0, sizeof ipHeader );
	unsigned char versionAndLen = 0x04;
	versionAndLen <<= 4;
	versionAndLen |= sizeof ipHeader / 4; //版本 + 头长度

	ipHeader.versionAndHeader = versionAndLen;
	*(unsigned short *)ipHeader.totalLen = htons( sizeof(IP_HEADER) + sizeof(TCP_HEADER) ); 

	ipHeader.ttl = 0xFF;
	ipHeader.hiProtovolType = 0x06;

	*(unsigned int *)(ipHeader.srcIpAddr) = inet_addr(lpszSrcIp);
	*(unsigned int *)(ipHeader.dstIpAddr) = inet_addr(lpszDstIp);
	*(unsigned short *)(ipHeader.headerCheckSum) = CheckSum( (unsigned short *)&ipHeader, sizeof ipHeader );

	ETHERNET_HEADER ethHeader;
	memset(ðHeader, 0, sizeof ethHeader);
	memcpy(ethHeader.dstMacAddr, dstMac, 6);
	memcpy(ethHeader.srcMacAddr, srcMac, 6);
	*(unsigned short *)ethHeader.ethernetType = htons(0x0800);

	byte packet[1024];
	memset(packet, 0, sizeof packet);

	memcpy(packet, ðHeader, sizeof ethHeader);
	memcpy(packet + sizeof ethHeader, &ipHeader, sizeof ipHeader);
	memcpy(packet + sizeof ethHeader + sizeof ipHeader, &tcpHeader, sizeof tcpHeader);
	
	int size = sizeof ethHeader + sizeof ipHeader + sizeof tcpHeader;
	pcap_sendpacket(handle, packet, size );
	printf("%-16s ------SYN-----> %-16s\n", lpszSrcIp, lpszDstIp );

	if ( NULL == handle )
	{
		printf("\nUnable to open the adapter. %s is not supported by WinPcap\n");
		return 0;
	}
	byte param[1024];
	memset(param, 0x00, sizeof param );
	memcpy(param, &srcPort, sizeof srcPort );
	memcpy(param + sizeof srcPort, handle, 512 );
	pcap_loop( handle, -1, HandlePacketCallBack, param );
	pcap_close(handle);	
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

你可能感兴趣的:(http,tcp,网络,三次握手,winpcap)