TCP三次握手原理与SYN攻击
本文内容包括以下几点
1.TCP三次握手四次挥手解析
2.迭代型服务器程序编写,并给出客户端,结合这一模式详细介绍Berkeley套接字的使用
3.介绍SYN攻击的原理
TCP连接建立,传输数据,连接释放上层图解。
结合此图来说明SYN攻击。SYN攻击发生在TCP连接的第二个阶段,服务器确认客户端同步信息(SYN),用32位确认号(ACK)确认SYN信息。
可以提出这样一个假设,客户端(client)给服务器发syn之后就不存在了,那么第二次握手失败,服务器会根据预先设置的超时时间继续做第二次握手,时间可以假设如下
第一轮第二次握手等待5s,过了五秒等不到客户端的第三次握手则继续第二轮第二次握手等待15s,依次迭代,直到等待时间超过某个阈值。(注:此处5s,15s均为假设值)。服务器不断的在进行第二次握手,消耗系统资源。
知道了SYN攻击的原理,那么如何进行SYN攻击?我们可以不断的发送TCP连接请求,同时把自己隐藏好,不让服务器发现。可以伪造IP,服务器根据IP来寻找客户端,由于IP是伪造的,所以TCP第二次握手会失败。伪造大量的IP可以大幅度消耗系统资源。从技术的角度上说,我们可以利用原始套接字伪造大量IP,从而构造大量数据包,利用原始套接字构造IP数据与服务器进行第一次握手,服务器忙于在处理队列中的连接,从而消耗系统资源。SYN攻击是TCP协议的bug造成,无法避免,除非重新修改TCP协议,但是这样子做不显示。
接下来是学习编写的代码,包括一个迭代型服务器和一个简易客户端,基本上每个编写网络程序的朋友第一次编写网络程序都类似下面的代码
服务器端:server.c
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <netinet/in.h> 5 #include <sys/socket.h> 6 7 int main(int argc, char **argv){ 8 9 /* variable */ 10 int sock_fd, connect_fd; 11 struct sockaddr_in server, client; 12 char buff[1024]; 13 int ret; 14 15 /* socket */ 16 sock_fd = socket(PF_INET, SOCK_STREAM, 0); 17 if(sock_fd < 0){ 18 perror("socket failed"); 19 exit(1); 20 } 21 22 server.sin_family = PF_INET; 23 //server.sin_addr.s_addr = INADDR_ANY; 24 server.sin_port = htons(5000); 25 if(inet_pton(PF_INET, "127.0.0.1", &server.sin_addr) < 0){ 26 perror("inet_pton"); 27 exit(1); 28 } 29 /* bind */ 30 ret = bind(sock_fd, (struct sockaddr*)&server, sizeof(server)); 31 if(ret < 0){ 32 perror("bind failed"); 33 exit(1); 34 } 35 36 /* listen */ 37 if(listen(sock_fd, 5)<0){ 38 perror("listen failed\n"); 39 exit(1); 40 } 41 /* accept */ 42 while(1){ 43 memset(buff, 0, sizeof(buff)); 44 connect_fd = accept(sock_fd, (struct sockaddr*)NULL,NULL); 45 46 if((ret = recv(connect_fd, buff, sizeof(buff), 0)) < 0){ 47 perror("recv"); 48 exit(1); 49 } 50 else if(ret == 0) 51 printf("read end\n"); 52 else{ 53 printf("receive message %s retval:%d\n", buff, ret); 54 } 55 close(connect_fd); 56 } 57 58 /* close */ 59 close(sock_fd); 60 return 0; 61 }
客户端:client.c
#include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #define LEN(str) (sizeof(char)*strlen(str)) int main(int argc, char **argv){ /* variable */ int sock_fd; struct sockaddr_in server; char buff[1024]; int ret; /* socket */ sock_fd = socket(PF_INET, SOCK_STREAM, 0); if(sock_fd < 0) { perror("socket failed"); exit(1); } server.sin_family = PF_INET; server.sin_port = htons(5000); if(inet_pton(PF_INET, "127.0.0.1", &server.sin_addr) < 0){ perror("inet_pton"); exit(1); } /* connect */ if((ret = connect(sock_fd, (struct sockaddr*)&server, sizeof(server)) )< 0){ perror("connect failed"); exit(1); } /* send buff */ sprintf(buff, "Hello World"); if(( ret = send(sock_fd, buff, LEN(buff), 0)) < 0){ perror("send"); exit(1); } printf("send msg\n"); /* close */ close(sock_fd); return 0; }
还是来个图,把套接字API之间的关系与TCP连接过程对应上
具体的API使用查看文档或者参考UNP1.关于TCP整个协议,想彻底理解的话,没有一定时间是做不到的,现在也仅限于握手挥手数据交换,至于流量控制,超时重传,数据包重排等功能暂时还没有更高的理解。
尽管上述迭代型服务器看上去运行成功,实际上这里面存在不少问题。将在下一篇文章记录。
接下来将复习迭代模型中,连接过程中的多种异常情况。并将复习情况记录blog。
最后,上传几个思维导图,关于Linux网络模块的,我一直坚信图片比文字,表格都要直观
作者水平有限,有错误的地方可以给我留言可以修改,以免误人子弟