本文內容包括以下幾點
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網絡模塊的,我一直堅信圖片比文字,表格都要直觀
作者水平有限,有錯誤的地方可以給我留言可以修改,以免誤人子弟