隊(duì)列及參數(shù)
server端的半連接隊(duì)列(syn隊(duì)列)
在三次握手協(xié)議中碎税,服務(wù)器維護(hù)一個(gè)半連接隊(duì)列乏屯,該隊(duì)列為每個(gè)客戶端的SYN包開設(shè)一個(gè)條目(服務(wù)端在接收到SYN包的時(shí)候茄蚯,就已經(jīng)創(chuàng)建了request_sock結(jié)構(gòu),存儲(chǔ)在半連接隊(duì)列中)蒲牧,該條目表明服務(wù)器已收到SYN包也榄,并向客戶發(fā)出確認(rèn)巡莹,正在等待客戶的確認(rèn)包(會(huì)進(jìn)行第二次握手發(fā)送SYN+ACK 的包加以確認(rèn))司志。這些條目所標(biāo)識(shí)的連接在服務(wù)器處于Syn_RECV狀態(tài)甜紫,當(dāng)服務(wù)器收到客戶的確認(rèn)包時(shí),刪除該條目骂远,服務(wù)器進(jìn)入ESTABLISHED狀態(tài)囚霸。
該隊(duì)列為SYN 隊(duì)列,長(zhǎng)度為 max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog) 激才,在機(jī)器的tcp_max_syn_backlog值在/proc/sys/net/ipv4/tcp_max_syn_backlog下配置拓型。
server端的完全連接隊(duì)列(accpet隊(duì)列)
當(dāng)?shù)谌挝帐謺r(shí),當(dāng)server接收到ACK 報(bào)之后瘸恼, 會(huì)進(jìn)入一個(gè)新的叫 accept 的隊(duì)列劣挫,該隊(duì)列的長(zhǎng)度為 min(backlog, somaxconn),默認(rèn)情況下东帅,somaxconn 的值為 128压固,表示最多有 129 的 ESTAB 的連接等待 accept(),而 backlog 的值則應(yīng)該是由 int listen(int sockfd, int backlog) 中的第二個(gè)參數(shù)指定靠闭,listen 里面的 backlog 可以有我們的應(yīng)用程序去定義的帐我。
當(dāng)Client發(fā)送SYN包之后掛了(syn flood攻擊
)
Client發(fā)送SYN包給Server后掛了,Server回給Client的SYN-ACK一直沒收到Client的ACK確認(rèn)愧膀,這個(gè)時(shí)候這個(gè)連接既沒建立起來拦键,也不能算失敗。這就需要一個(gè)超時(shí)時(shí)間讓Server將這個(gè)連接斷開檩淋,否則這個(gè)連接就會(huì)一直占用Server的SYN連接隊(duì)列中的一個(gè)位置芬为,大量這樣的連接就會(huì)將Server的SYN連接隊(duì)列耗盡,讓正常的連接無法得到處理蟀悦。
目前媚朦,Linux下默認(rèn)會(huì)進(jìn)行5次重發(fā)SYN-ACK包,重試的間隔時(shí)間從1s開始熬芜,下次的重試間隔時(shí)間是前一次的雙倍莲镣,5次的重試時(shí)間間隔為1s, 2s, 4s, 8s, 16s,總共31s涎拉,第5次發(fā)出后還要等32s都知道第5次也超時(shí)了瑞侮,所以的圆,總共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才會(huì)把斷開這個(gè)連接半火。由于越妈,SYN超時(shí)需要63秒,那么就給攻擊者一個(gè)攻擊服務(wù)器的機(jī)會(huì)钮糖,攻擊者在短時(shí)間內(nèi)發(fā)送大量的SYN包給Server(俗稱 SYN flood 攻擊)梅掠,用于耗盡Server的SYN隊(duì)列。對(duì)于應(yīng)對(duì)SYN 過多的問題店归,linux提供了幾個(gè)TCP參數(shù):tcp_syncookies阎抒、tcp_synack_retries、tcp_max_syn_backlog消痛、tcp_abort_on_overflow 來調(diào)整應(yīng)對(duì)且叁。
net.ipv4.tcp_synack_retries #內(nèi)核放棄連接之前發(fā)送SYN+ACK包的數(shù)量
net.ipv4.tcp_syn_retries #內(nèi)核放棄建立連接之前發(fā)送SYN包的數(shù)量
為了應(yīng)對(duì)SYNflooding(即客戶端只發(fā)送SYN包發(fā)起握手而不回應(yīng)ACK完成連接建立,填滿server端的半連接隊(duì)列秩伞,讓它無法處理正常的握手請(qǐng)求)逞带,Linux實(shí)現(xiàn)了一種稱為SYNcookie的機(jī)制,通過net.ipv4.tcp_syncookies控制纱新,設(shè)置為1表示開啟展氓。簡(jiǎn)單說SYNcookie就是將連接信息編碼在ISN(initialsequencenumber)中返回給客戶端,這時(shí)server不需要將半連接保存在隊(duì)列中脸爱,而是利用客戶端隨后發(fā)來的ACK帶回的ISN還原連接信息遇汞,以完成連接的建立,避免了半連接隊(duì)列被攻擊SYN包填滿阅羹。
當(dāng)syn隊(duì)列滿的情況(tcp_abort_on_overflow
)
對(duì)于SYN半連接隊(duì)列的大小是由(/proc/sys/net/ipv4/tcp_max_syn_backlog)這個(gè)內(nèi)核參數(shù)控制的勺疼,有些內(nèi)核似乎也受listen的backlog參數(shù)影響,取得是兩個(gè)值的最小值捏鱼。當(dāng)這個(gè)隊(duì)列滿了执庐,不開啟syncookies的時(shí)候,Server會(huì)丟棄新來的SYN包导梆,而Client端在多次重發(fā)SYN包得不到響應(yīng)而返回(connection time out
)錯(cuò)誤轨淌。但是,當(dāng)Server端開啟了syncookies=1看尼,那么SYN半連接隊(duì)列就沒有邏輯上的最大值了递鹉,并且/proc/sys/net/ipv4/tcp_max_syn_backlog設(shè)置的值也會(huì)被忽略。
Client端在多次重發(fā)SYN包得不到響應(yīng)而返回
connection time out
錯(cuò)誤
查看
netstat -s | grep LISTEN
4375 SYNs to LISTEN sockets dropped
當(dāng)accept隊(duì)列滿的情況
當(dāng)accept隊(duì)列滿了之后藏斩,即使client繼續(xù)向server發(fā)送ACK的包躏结,也會(huì)不被響應(yīng),此時(shí)ListenOverflows+1狰域,同時(shí)server通過/proc/sys/net/ipv4/tcp_abort_on_overflow來決定如何返回媳拴,0表示直接丟棄該ACK黄橘,1表示發(fā)送RST通知client;相應(yīng)的屈溉,client則會(huì)分別返回read timeout
或者 connection reset by peer
塞关。
client則會(huì)分別返回
read timeout
或者connection reset by peer
查看
root@b5dbe93bcb04:/opt# netstat -s | grep listen
22438 times the listen queue of a socket overflowed
accept隊(duì)列滿了,對(duì) syn隊(duì)列也有影響子巾,在代碼 net/ipv4/tcp_ipv4.c :
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
/*tcp_syncookies為2 進(jìn)行syn cookie
tcp_syncookies為1 且request隊(duì)列滿了 進(jìn)行syn cookie處理
tcp_syncookies為0 且request隊(duì)列滿了 將該syn報(bào)文drop掉
*/
if ((sysctl_tcp_syncookies == 2 ||
inet_csk_reqsk_queue_is_full(sk)) && !isn) {
want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
if (!want_cookie)
goto drop;
}
/* Accept backlog is full. If we have already queued enough
* of warm entries in syn queue, drop request.
*/
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
goto drop;
}
accept隊(duì)列大多數(shù)情況下會(huì)比較小帆赢,所以會(huì)出現(xiàn)SYN 隊(duì)列沒有滿,而ACCEPT 隊(duì)列滿了的情況线梗,此時(shí)會(huì)按照tcp_aborton_overflow來決定直接丟棄椰于,還是返回拒絕RST。 而如果啟用了syncookies缠导,那么syncookies會(huì)開啟廉羔,限制SYN包進(jìn)入的速度溉痢。
當(dāng)系統(tǒng)丟棄最后的 ACK僻造,而系統(tǒng)中還有一個(gè) net.ipv4.tcp_synack_retries 設(shè)置時(shí),Linux 會(huì)重新發(fā)送 SYN ACK 包孩饼。而客戶端收到多個(gè) SYN ACK 包髓削,則會(huì)認(rèn)為之前的 ACK 丟包了。于是促使客戶端再次發(fā)送 ACK 镀娶,在 accept隊(duì)列有空閑的時(shí)候最終完成連接立膛。若 accept隊(duì)列始終滿員,則最終客戶端收到 RST 包梯码。
doc
- Linux SYN Backlog and somaxconn
- TCP/IP協(xié)議中backlog參數(shù)
- TCP SOCKET中backlog參數(shù)的用途是什么宝泵?
- 了解tcp底層知識(shí)
- 再理解tcp backlog
- Linux TCP隊(duì)列相關(guān)參數(shù)的總結(jié)
- TCP全連接隊(duì)列和半連接隊(duì)列已滿之后的連接建立過程抓包分析
- linux、mysql轩娶、nginx儿奶、tomcat 環(huán)境下壓力測(cè)試的主要調(diào)試參數(shù)
- 從TCP三次握手說起–淺析TCP協(xié)議中的疑難雜癥(1)
- 從TCP三次握手說起–淺析TCP協(xié)議中的疑難雜癥(2)