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,這個網上資料很少,我是先抓包研究的,最後結果如下:
經抓包分析得知,最後傳送資料時發的是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)這樣類似的寫法,而是直接讀取報頭中的報頭長度欄位,這樣會更精確些,因為我們不用知道伺服器有沒有新增選項資料。
最後的結果:
最後貼上全部原始碼
#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;
}
相關推薦
winpcap實現從TCP三次握手到傳送http請求
之前的文章我都是貼出了協議的格式,對具體欄位沒有具體說明,今天在這裡補充一下。 /* IP報文格式 0 8 16 32 +---------
從 TCP 三次握手說起:淺析TCP協議中的疑難雜症 ( 1 )
從 TCP 三次握手說起:淺析TCP協議中的疑難雜症 ( 1 ) 說到TCP協議,相信大家都比較熟悉了,對於TCP協議總能說個一二三來,但是TCP協議又是一個非常複雜的協議,其中有不少細節點讓人頭疼點。本文就是來說說這些頭疼點的,淺談一些TCP的疑難雜症。那麼從
用wireshark抓包分析TCP三次握手、四次揮手以及TCP實現可靠傳輸的機制(轉)
關於TCP三次握手和四次揮手大家都在《計算機網路》課程裡學過,還記得當時高超老師耐心地講解。大學裡我遇到的最好的老師大概就是這位了,雖然他只給我講過《java程式設計》和《計算機網路》,但每次課幾乎都動手敲程式碼或者當場做實驗。好了不扯了,下面進入正題。 關
記一次壓測問題定位:connection reset by peer,TCP三次握手後服務端傳送RST
問題描述 這兩天用Go做一個比較簡單的task:後端有HTTPServer和TCPServer。客戶端通過http接入到HTTPServer,HTTPServer通過RPC將請求傳送到TCPServer,所有的業務邏輯都由TCPServer處理。 壓測:自己的ma
TCP三次握手和四次揮手為何只傳送三個包?
首先說一下三次握手過程 一下摘自wiki handshake Establishing a normal TCP connection requires three separate steps: The first host (Alice) sends the s
TCP三次握手報文 例項詳解&&syn flood C/C++ 完整程式碼實現
在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線。 第一次握手: 建立連線時,客戶端傳送syn包到伺服器,並進入SYN_SENT狀態,等待伺服器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。 第二次握手
TCP三次握手,四次揮手(從狀態的角度分析)
但是,我發覺我的知識來源大多來自《計算機網路-自頂向下》那本,這本書沒有過多的考慮TCP三次握手中的相關狀態轉移細節,導致當時回答的並不是特別好,這次決定好好把這塊知識好好鞏固一下。 首先,我們先來一張大家都非常熟悉的圖: 相信大家對這張圖已經熟得不能再
五層協議及tcp三次握手四次揮手
p地址 電平 揮手 syn 服務端 局域網 dhcp 網絡層 數據 一.五層協議:物理層:傳送數據 通過高低電平傳輸數據數據鏈路層:ethernet 以太網協議 必須有一塊網卡:12位16進制數,前六位位廠商編號,後六位為流水線號 (定位到某一臺機
TCP/IP三次握手和HTTP過程
等待 自身 text ssi 描述 套接字 網絡連接 計算 中間 1、TCP連接 手機能夠使用聯網功能是因為手機底層實現了TCP/IP協議,可以使手機終端通過無線網絡建立TCP連接。TCP協議可以對上層網絡提供接口,使上層網絡數據的傳輸建立在“無差別”的網絡之上。 建立起
3-TCP三次握手
三次 netstat 的確 需要 ber 客戶 保護 rec push TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接: 位碼即tcp標誌位,有6種標示:SYN(synchronous建立聯機) ACK(acknowledgement
TCP三次握手和四次揮手
tcp握手和揮手TCP報文的頭部信息: SEQ SYN ACK FIN此時會用上ACK : TCP協議規定,只有ACK=1時有效,也規定連接建立後所有發送的報文的ACK必須為1SYN(SYNchronization) : 在連接建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連接請求報文。對方若同
白話TCP三次握手
tcp三次握手 tcp syn established ack 眾所周知,TCP是可靠傳輸,那麽什麽叫可靠呢?簡單的講就是二者通信,只有當彼此都知道自己以及對方收發消息都正常時候,然後再進行數據傳輸。 而三次握手的目的就是為了確認雙方收發消息都沒問題。 首
基於 Wireshark 學習 TCP 三次握手
tcp Wireshark(前稱Ethereal)是一個網絡封包分析軟件。網絡封包分析軟件的功能是擷取網絡封包,並盡可能顯示出最為詳細的網絡封包資料。Wireshark使用WinPCAP作為接口,直接與網卡進行數據報文交換。 同類型的軟件有:cain、sniffer WinPcap是用於網絡封包抓取的一
TCP三次握手
標示 syn sequence lin span 可靠 style -1 成功 TCP三次握手。 TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接。 tcp標誌位,有6種標示:SYN(synchronous建立聯機) ACK(ac
TCP三次握手與四次分手
int 有效 tcp三次握手 osi height -1 rcv time 就會 三次握手 解釋:客戶端A和服務器B剛開始處於CLOSED狀態,兩者之間沒有任何聯系,A主動打開,B被動打開由 CLOSED進入LISTEN狀態,這是A發送一個SYN=1的標
TCP 三次握手(相當於寄信需要回執,第一次握手:我寄給你一封信。第二次握手:你回我一封信。第三次握手:我再給你一個回執,這樣你才能確認我收到信了)
需要 flags 並發 如果 details live 丟失 tail 進行 TCP 連接是通過三次握手進行初始化的。三次握手的目的是同步連接雙方的序列號和確認號並交換 TCP 窗口大小信息。以下步驟概述了通常情況下客戶端計算機聯系服務器計算機的過程: 1. 客戶端向服務器
tcp三次握手 四次揮手 (轉)
分享 cli fcm 是我 chm 2msl 比較 為什麽 需要 轉自: http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而斷開連接則需要四次握手。整個過程如下圖所示: 先來看
TCP三次握手和四次揮手詳解
tcp三次握手和四次揮手詳解TCP(Transmission Control Protocol)網絡傳輸控制協議,是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,數據傳輸前建立連接的工作要經過三次握手,數據傳輸後斷開連接的工作要經過四次揮手。工作過程TCP標誌位:TCP共有6個標誌位,分別是:SYN(s
淺談TCP三次握手和四次分手
必須 通信 服務 嘗試 pro 標示 cnblogs 通話 應該 TCP(Transmission Control Protocol傳輸控制協議)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議提供可靠的連接服務,采用三次握手確認建立一個連接,比如我們去訪問
一次經典的tcp三次握手
ges 但是 字節 alt 經典的 二次 pan 連接 分享 TCP報頭 在三次握手中使用的字段: 32位序列號 seq:表示的是本次報文發送的數據的第一個字節的序號。 32位確認號:ack 表示期望下一次應該接受到的報文的第一個字節的序號,若ack = N則表示,到序