tcp三次握手的资料.doc_第1页
tcp三次握手的资料.doc_第2页
tcp三次握手的资料.doc_第3页
tcp三次握手的资料.doc_第4页
tcp三次握手的资料.doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

次我用winpcap成功发送一个UDP数据包到服务器。 相比较TCP要复杂的多, tcp不但要完成开始连接的三次握手, 还要处理数据包的序列号。 下面是tcp七次握手示意图: 下面我就来模拟一个TCP客服端,发送一个连接到服务器, 服务器之后断开。这样就是7次握手, 不含其他数据包。首先我们做一个tcp服务器, 最好是一个公网的, 这样连接就更有真实性。服务器代码:view plaincopy to clipboardprint?#include #include #include #include #pragma comment (lib,ws2_32.lib) SOCKET tcpServerSocket = 0; SOCKADDR_IN tcpServerAddr = 0 ; const int backlog = SOMAXCONN; WSADATA wsaData = 0 ; int ret_code; #define PORT 7456 /server port #define IPSTRING 122.*.*.* /server ip / void error(const char* errstr, int errcode) printf(Error: %sn, errstr); printf(Error Code: %sn, errcode); void error_exit(const char* errstr, int errcode) error(errstr, errcode); exit(errcode); void main() ret_code = WSAStartup( MAKEWORD( 2, 2 ), &wsaData); if ( ret_code != 0 ) error_exit(WSAStartup error, ret_code); / if(tcpServerSocket = socket(AF_INET, SOCK_STREAM, 0) = INVALID_SOCKET) error_exit(socket error, WSAGetLastError(); /IP tcpServerAddr.sin_family = AF_INET; tcpServerAddr.sin_port = htons(PORT); tcpServerAddr.sin_addr.S_un.S_addr = inet_addr(IPSTRING); if(bind(tcpServerSocket, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr) = SOCKET_ERROR) error_exit(bind error, WSAGetLastError(); if(listen(tcpServerSocket, backlog) = SOCKET_ERROR) error_exit(listen error, WSAGetLastError(); while(true) SOCKET tcpClientSocket = 0; SOCKADDR_IN tcpClientAddr = 0 ; int tcpClientAddrLen = sizeof(SOCKADDR_IN); if(tcpClientSocket = accept(tcpServerSocket, (struct sockaddr *)&tcpClientAddr, &tcpClientAddrLen) = INVALID_SOCKET) error_exit(accept error, WSAGetLastError(); continue; printf(From IP = %s Port = %dn, inet_ntoa(tcpClientAddr.sin_addr), ntohs(tcpClientAddr.sin_port); / /recv /send closesocket(tcpClientSocket); #include #include #include #include #pragma comment (lib,ws2_32.lib)SOCKET tcpServerSocket = 0;SOCKADDR_IN tcpServerAddr = 0 ;const int backlog = SOMAXCONN;WSADATA wsaData = 0 ; int ret_code;#define PORT 7456 /server port#define IPSTRING 122.*.*.* /server ip/void error(const char* errstr, int errcode) printf(Error: %sn, errstr); printf(Error Code: %sn, errcode);void error_exit(const char* errstr, int errcode) error(errstr, errcode); exit(errcode);void main() ret_code = WSAStartup( MAKEWORD( 2, 2 ), &wsaData); if ( ret_code != 0 ) error_exit(WSAStartup error, ret_code); / if(tcpServerSocket = socket(AF_INET, SOCK_STREAM, 0) = INVALID_SOCKET) error_exit(socket error, WSAGetLastError(); /IP tcpServerAddr.sin_family = AF_INET; tcpServerAddr.sin_port = htons(PORT); tcpServerAddr.sin_addr.S_un.S_addr = inet_addr(IPSTRING); if(bind(tcpServerSocket, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr) = SOCKET_ERROR) error_exit(bind error, WSAGetLastError(); if(listen(tcpServerSocket, backlog) = SOCKET_ERROR) error_exit(listen error, WSAGetLastError(); while(true) SOCKET tcpClientSocket = 0; SOCKADDR_IN tcpClientAddr = 0 ; int tcpClientAddrLen = sizeof(SOCKADDR_IN); if(tcpClientSocket = accept(tcpServerSocket, (struct sockaddr *)&tcpClientAddr, &tcpClientAddrLen) = INVALID_SOCKET) error_exit(accept error, WSAGetLastError(); continue; printf(From IP = %s Port = %dn, inet_ntoa(tcpClientAddr.sin_addr), ntohs(tcpClientAddr.sin_port); / /recv /send closesocket(tcpClientSocket); 好了服务器是做好了, 现在主要是做客服端了。在发送数据包之前, 我们要知道数据包的结构, 对一个TCP数据包结构像这个样子:【以太网头】【IP头】【TCP头】【数据】由于握手过程数据可以空, 所以只有三个部分。 各种数据包头如下声明(注意我这里给出的是小端模式), 大部分数从linux系统里面copy过来。 对数据包详细信息, 这里就不多说了。view plaincopy to clipboardprint?#include #pragma comment(lib, wpcap.lib) #include #pragma comment(lib, Ws2_32.lib) #define ETHER_ADDR_LEN 6 /from linuxs ethernet.h #define ETHERTYPE_IP 0x0800 /* IP */ /以太网数据头 struct ether_header u_char ether_dhostETHER_ADDR_LEN; u_char ether_shostETHER_ADDR_LEN; u_short ether_type; /如果上一层为IP协议。则ether_type的值就是0x0800 ; /IP数据头 struct ip_header /小端模式 unsigned char ihl:4; /ip header length unsigned char version:4; /version u_char tos; /type of service u_short tot_len; /total length u_short id; /identification u_short frag_off; /fragment offset u_char ttl; /time to live u_char protocol; /protocol type u_short check; /check sum u_int saddr; /source address u_int daddr; /destination address ; /tcp数据头 struct tcp_header /小端模式 u_int16_t source; u_int16_t dest; u_int32_t seq; u_int32_t ack_seq; u_int16_t res1:4; u_int16_t doff:4; u_int16_t fin:1; u_int16_t syn:1; u_int16_t rst:1; u_int16_t psh:1; u_int16_t ack:1; u_int16_t urg:1; u_int16_t res2:2; u_int16_t window; u_int16_t check; u_int16_t urg_ptr; ; /tcp和udp计算校验和是的伪头 struct psd_header u_int32_t sourceip; /源IP地址 u_int32_t destip; /目的IP地址 u_char mbz; /置空(0) u_char ptcl; /协议类型 u_int16_t plen; /TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度 单位:字节) ; #include #pragma comment(lib, wpcap.lib)#include #pragma comment(lib, Ws2_32.lib)#define ETHER_ADDR_LEN 6/from linuxs ethernet.h#define ETHERTYPE_IP 0x0800 /* IP */以太网数据头struct ether_header u_char ether_dhostETHER_ADDR_LEN; u_char ether_shostETHER_ADDR_LEN; u_short ether_type; /如果上一层为IP协议。则ether_type的值就是0x0800;/IP数据头struct ip_header /小端模式 unsigned char ihl:4; /ip header length unsigned char version:4; /version u_char tos; /type of service u_short tot_len; /total length u_short id; /identification u_short frag_off; /fragment offset u_char ttl; /time to live u_char protocol; /protocol type u_short check; /check sum u_int saddr; /source address u_int daddr; /destination address ;/tcp数据头struct tcp_header /小端模式 u_int16_t source; u_int16_t dest; u_int32_t seq; u_int32_t ack_seq; u_int16_t res1:4; u_int16_t doff:4; u_int16_t fin:1; u_int16_t syn:1; u_int16_t rst:1; u_int16_t psh:1; u_int16_t ack:1; u_int16_t urg:1; u_int16_t res2:2; u_int16_t window; u_int16_t check; u_int16_t urg_ptr;/tcp和udp计算校验和是的伪头struct psd_header u_int32_t sourceip; /源IP地址 u_int32_t destip; /目的IP地址 u_char mbz; /置空(0) u_char ptcl; /协议类型 u_int16_t plen; /TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度 单位:字节); 好了, 现在可以发送数据包了, 我们发送四个数据包, 服务器回复三个数据包。1. client发送SYN数据包2. 接收server syn和ack包3. 发送ack包4. 接收fin数据包5. 回复ack6. 发送fin7. 接收ack这里我用两个线程来处理, 主线程接收数据包(pcap_loop), 一个子线程负责发送数据包(send_packet_handle)。 在构建数据报的时候一定要注意 TCP的seq 和ack_seq的更新, 下一个发送的seq值等于上一个收到的ack_seq。 下一个seq_ack为上一个接收的seq+1. 这里只是一个简单的模拟程序, 没有考虑两个线程之间的数据同步。view plaincopy to clipboardprint?char* device = DeviceNPF_06864041-9387-44DC-AF44-37779B0F2E9E; pcap_t* adhandle = NULL; char errbufPCAP_ERRBUF_SIZE = 0 ; unsigned int netmask=0xffffff; struct bpf_program fcode; char* filter = tcp; #include #define DSTPORT 7456 #define SRCPORT 7456 #define DSTIP *.*.*.* #define SRCIP *.*.*.* bool isShouldReply = false; /step = 0, 接收 syn ack /step = 1, 接收 fin /step = 2,接收 fin之后ack int step = 0; /分别表示发送段和接收端开始系列号 unsigned int next_seq = 0x42345678; unsigned int next_ack_seq = 0; /用一个线程检测从目的地发过来的数据包. /另一个线程向目的地发送数据包. /负责发送数据包 void send_packet_handle(void* arg); /负责接收数据包, pcap_loop参数用于回调 void my_pcap_handler(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); unsigned short do_check_sum(void* buffer, int len); char* uint_to_addr(u_int addr); void main() if(adhandle = pcap_open(device, 0x10000, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) = NULL) printf(pcap_open error : %sn, errbuf); return; if(pcap_compile(adhandle, &fcode, filter, 1, netmask) = -1) printf(pcap_compile error : %sn, pcap_geterr(adhandle); return; if(pcap_setfilter(adhandle, &fcode) = -1) printf(pcap_setfilter error : %sn, pcap_geterr(adhandle); return; unsigned long p = _beginthread(send_packet_handle, 0, NULL); pcap_loop(adhandle, 0, my_pcap_handler, NULL); void my_pcap_handler(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) ether_header* pe_header = (ether_header*)pkt_data; if(pe_header-ether_type = htons(ETHERTYPE_IP) ip_header* p_ip_header = (ip_header*)(pkt_data + sizeof(ether_header); if(p_ip_header-saddr = p_ip_header-daddr) printf(%sn, uint_to_addr(p_ip_header-saddr); /IP地址检验 if(p_ip_header-protocol = IPPROTO_TCP | (p_ip_header-saddr = inet_addr(DSTIP) & p_ip_header-daddr = inet_addr(SRCIP) | (p_ip_header-saddr = inet_addr(SRCIP) & p_ip_header-daddr = inet_addr(DSTIP) tcp_header* ptcpHeader = (tcp_header*)(pkt_data + sizeof(ether_header) + p_ip_header-ihl * 4); /端口检验 if(ptcpHeader-dest = htons(DSTPORT) | ptcpHeader-source = htons(DSTPORT) ) /打印信息 printf(%s:%d t- , uint_to_addr(p_ip_header-saddr), ntohs(ptcpHeader-source); printf(%s:%d len = %u type: , uint_to_addr(p_ip_header-daddr),ntohs(ptcpHeader-dest), ntohs(p_ip_header-tot_len) - sizeof(ip_header) - sizeof(tcp_header); if(ptcpHeader-syn = 1) printf(SYN = %u , ntohl(ptcpHeader-seq); if(ptcpHeader-ack = 1) printf(ACK = %u , ntohl(ptcpHeader-ack_seq); if(ptcpHeader-fin = 1) printf(FIN = %u , ntohl(ptcpHeader-seq); if(ptcpHeader-rst = 1) printf(RST ); if(ptcpHeader-psh = 1) printf(PSH ); printf(n); if(step = 0 & ptcpHeader-syn = 1 & ptcpHeader-ack = 1 & ptcpHeader-ack_seq = htonl(next_seq + 1) next_ack_seq = ntohl(ptcpHeader-seq) + 1; next_seq = ntohl(ptcpHeader-ack_seq); isShouldReply = true; else if(step = 1 & ptcpHeader-fin = 1) next_ack_seq = ntohl(ptcpHeader-seq) + 1; next_seq = ntohl(ptcpHeader-ack_seq); isShouldReply = true; /* else if(step = 2 & ptcpHeader-ack = 1 & ptcpHeader-seq = next_ack_seq) isShouldReply = true; */ void send_packet_handle(void* arg) /三次握手不含数据 char tcp_buffer54 = 0 ; /14 以太网头部, 20 ip头, 20 tcp头, 没有其它数据 ether_header* pether_header = (ether_header*)tcp_buffer; ip_header* pip_header = (ip_header*)(tcp_buffer + sizeof(ether_header); tcp_header* ptcp_header = (tcp_header*)(tcp_buffer + sizeof(ether_header) + sizeof(ip_header); /设置以太网头部 /所有MAC位置1 /unsigned char mac = 0,238,238,129,65,238,0,29,96,102,102,15; /memcpy(pether_header, mac, 12); memset(pether_header, 1, 12); pether_header-ether_type = htons(ETHERTYPE_IP); /设置IP头 pip_header-ihl = sizeof(ip_header) / 4; pip_header-version = 4; pip_header-tos = 0; pip_header-tot_len = htons(sizeof(tcp_buffer) - sizeof(ether_header); /12288 pip_header-id = 616; /616 pip_header-frag_off = 64; pip_header-ttl = 128; pip_header-protocol = IPPROTO_TCP; pip_header-check = 0; pip_header-saddr = inet_addr(SRCIP); pip_header-daddr = inet_addr(DSTIP); pip_header-check = in_cksum(u_int16_t*)pip_header, sizeof(ip_header); /设置TCP头 ptcp_header-source = htons(SRCPORT); ptcp_header-dest = htons(DSTPORT); ptcp_header-seq = htonl(next_seq); ptcp_header-ack_seq = htonl(next_ack_seq); ptcp_header-doff = sizeof(tcp_header) / 4; ptcp_header-res1 = 0; ptcp_header-res2 = 0; ptcp_header-fin = 0; ptcp_header-syn = 1; ptcp_header-rst = 0; ptcp_header-psh = 0; ptcp_header-ack = 0; ptcp_header-urg = 0; ptcp_header-window = 65535; ptcp_header-check = 0; ptcp_header-urg_ptr = 0; ptcp_header-check = do_check_sum(ptcp_header, sizeof(tcp_header); /发送一个SYN包到对方 if(pcap_sendpacket(adhandle, (const u_char*)tcp_buffer, sizeof(tcp_buffer) = -1) printf(pcap_sendpacket errorn); return; while(true) if(isShouldReply) break; Sleep(100); /发送一个ACK包到对方 ptcp_header-syn = 0; ptcp_header-ack = 1; ptcp_header-seq = htonl(next_seq); ptcp_header-ack_seq = htonl(next_ack_seq); ptcp_header-check = 0; ptcp_header-check = do_check_sum(ptcp_header, sizeof(tcp_header); isShouldReply = false; step = 1; if(pcap_sendpacket(adhandle, (const u_char*)tcp_buffer, sizeof(tcp_buffer) = -1) printf(pcap_sendpacket errorn); return; while(true) if(isShouldReply) break; Sleep(100); /发送fin回复的ack包 ptcp_header-ack = 1; ptcp_header-seq = htonl(next_seq); ptcp_header-ack_seq = htonl(next_ack_seq); ptcp_header-check = 0; ptcp_header-check = do_check_sum(ptcp_header, sizeof(tcp_header); isShouldReply = false; if(pcap_sendpacket(adhandle, (const u_char*)tcp_buffer, sizeof(tcp_buffer) = -1) printf(pcap_sendpacket errorn); return; /接着发送一个fin, ack包 ptcp_header-ack = 1; ptcp_header-fin = 1; ptcp_header-seq = htonl(next_seq); ptcp_header-ack_seq = htonl(next_ack_seq); ptcp_header-check = 0; ptcp_header-check = do_check_sum(ptcp_header, sizeof(tcp_header); isShouldReply = false; step = 2; if(pcap_sendpacket(adhandle, (const u_char*)tcp_buffer, sizeof(tcp_buffer) = -1) printf(pcap_sendpacket errorn); return; printf(Finishedn); char* uint_to_addr(u_int addr) in_addr inaddr; inaddr.S_un.S_addr = addr; return inet_ntoa(inaddr); unsigned short do_check_sum(void* buffer, int len) char buffer2128 = 0 ; psd_header* psd = (psd_header*)buffer2; psd-sourceip = inet_addr(SRCIP); psd-destip = inet_addr(DSTIP); psd-ptcl = IPPROTO_TCP; psd-plen = htons(sizeof(tcp_header); memcpy(buffer2 + sizeof(psd_header), buffer, sizeof(tcp_header); return in_cksum(u_int16_t*)buffer2, sizeof(psd_header) + sizeof(tcp_header); char* device = DeviceNPF_06864041-9387-44DC-AF44-37779B0F2E9E;pcap_t* adhandle = NULL;char errbufPCAP_ERRBUF_SIZE = 0 ;unsigned int netmask=0xffffff; struct bpf_program fcode;char* filter = tcp;#include #define DSTPORT 7456#define SRCPORT 7456#define DSTIP *.*.*.*#define SRCIP *.*.*.*bool isShouldReply = false;/step = 0, 接收 syn ack/step = 1, 接收 fin/step = 2,接收 fin之后ackint step = 0; /分别表示发送段和接收端开始系列号unsigned int next_seq = 0x42345678;unsigned int next_ack_seq = 0;/用一个线程检测从目的地发过来的数据包./另一个线程向目的地发送数据包./负责发送数据包void s

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论