listen--監聽數量
#include <sys/socket.h>
int listen(int sockfd, int backlog);
/* backlog指定了該套接口排隊的最大連接個數 */
調用listen導致套接口從CLOSED狀態轉換到LISTEN狀態。
監聽窗口維持兩個隊列(隊列的大小與backlog有關):
- 未完成隊列,每個這樣的SYN分節對應一項;已由某個客戶發出並到達服務器,而服務器正在等待完成相應的TCP三次握手,此套接口處於SYN_RCVD狀態。
- 完成隊列,完成TCP三次握手過程的每一項;該套接口處於ESTABLISHED狀態。
問題來了,如何動態的改變listen監聽的個數呢?
如果指定值在源代碼中是一個常值,那么增長其大小需要重新編譯服務器程序。那么,我們可以為它設定一個缺省值,不過允許通過命令行選項或者環境變量來覆寫該值。
void Listen(int fd, int backlog) { char *ptr; if((ptr = getenv("LISTENQ")) != NULL) backlog = atoi(ptr); if(listen(fd, backlog) < 0) printf("listen error\n"); }
隊列已滿的情況,如何處理?
當一個客戶SYN到達時,若這個隊列是滿的,TCP就忽略該分節,也就是不會發送RST。
這么做的原因在於,隊列已滿的情況是暫時的,客戶TCP如果沒收收到RST,就會重發SYN,在隊列有空閑的時候處理該請求。如果服務器TCP立即響應一個RST,客戶的connect調用就會立即返回一個錯誤,強制應用進程處理這種情況,而不會再次重發SYN。而且客戶端也不無區別該套接口的狀態,是“隊列已滿”還是“該端口沒有在監聽”。
SYN泛濫攻擊
向某一目標服務器發送大量的SYN,用以填滿一個或多個TCP端口的未完成隊列。每個SYN的源IP地址都置成隨機數(IP欺騙),這樣防止攻擊服務器獲悉黑客的真實IP地址。通過偽造的SYN裝滿未完成連接隊列,使得合法的SYN不能排上隊,導致針對合法用戶的服務被拒絕。
防御方法:
- 針對服務器主機的方法。增加連接緩沖隊列長度和縮短連接請求占用緩沖隊列的超時時間。該方式最簡單,被很多操作系統采用,但防御性能也最弱。
- 針對路由器過濾的方法。由於DDoS攻擊,包括SYN-Flood,都使用地址偽裝技術,所以在路由器上使用規則過濾掉被認為地址偽裝的包,會有效的遏制攻擊流量。
- 針對防火牆的方法。在SYN請求連接到真正的服務器之前,使用基於防火牆的網關來測試其合法性。它是一種被普遍采用的專門針對SYN-Flood攻擊的防御機制。
參考
Unix網絡編程
基於主動網的SYN攻擊防御