linux 內核參數tcp_max_syn_backlog對應的隊列最小長度

環境:centos7.4 內核版本3.10html

內核參數net.ipv4.tcp_max_syn_backlog定義了處於SYN_RECV的TCP最大鏈接數,當處於SYN_RECV狀態的TCP鏈接數超過tcp_max_syn_backlog後,會丟棄後續的SYN報文。centos

爲了測試上述結論,首先將tcp_syncookies設置爲0,並將net.ipv4.tcp_max_syn_backlog設置爲2,測試拓撲爲:1.1.1.1(client)------1.1.1.2:19090(server),在client端添加以下iptables規則,在發送完SYN報文後,底層丟棄接收到的SYN/ACK報文cookie

iptables -t filter -I INPUT -p tcp -m tcp --sport 19090  --tcp-flag SYN,ACK SYN,ACK -j DROP

但在實際測試中發現處於SYN_RECV狀態的鏈接數能夠大於設置的值2,且若是此時觸發新的鏈接,該鏈接也能正常建鏈。難道tcp_max_syn_backlog沒有生效?經過查找文檔,發如今這篇文章中給出了緣由。在內核net/core/request_sock.c中的實現以下,紅色字體代碼給出了計算tcp_max_syn_backlog的最小值。sysctl_max_syn_backlog的值對應手動設置的net.ipv4.tcp_max_syn_backlog的值。dom

int reqsk_queue_alloc(struct request_sock_queue *queue, unsigned int nr_table_entries) { size_t lopt_size = sizeof(struct listen_sock); struct listen_sock *lopt;  nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog); nr_table_entries = max_t(u32, nr_table_entries, 8); nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); lopt_size += nr_table_entries * sizeof(struct request_sock *); if (lopt_size > PAGE_SIZE) lopt = vzalloc(lopt_size); else lopt = kzalloc(lopt_size, GFP_KERNEL); if (lopt == NULL) return -ENOMEM;     for (lopt->max_qlen_log = 3; (1 << lopt->max_qlen_log) < nr_table_entries; lopt->max_qlen_log++); get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd)); rwlock_init(&queue->syn_wait_lock); queue->rskq_accept_head = NULL; lopt->nr_table_entries = nr_table_entries; write_lock_bh(&queue->syn_wait_lock); queue->listen_opt = lopt; write_unlock_bh(&queue->syn_wait_lock); return 0; }

能夠看到當sysctl_max_syn_backlog=2時,計算過程以下:tcp

    • nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog);nr_table_entries爲listen backlog的值,即系統net.core.somaxconn的值,默認128。此處獲取nr_table_entries和sysctl_max_syn_backlog的最小值,得出nr_table_entries=2
    • nr_table_entries = max_t(u32, nr_table_entries, 8);計算nr_table_entries和8的最大值,此時得出nr_table_entries=8
    • nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);計算(1UL << (ilog2((9) - 1) + 1)),即1<<3=16。這就是net.ipv4.tcp_max_syn_backlog的最小值

使用以下腳本模擬syn flood攻擊,當 watch 'netstat -antp|grep SYN_RECV|wc -l' 等於16時,換一臺機器鏈接server發現鏈接超時;設置tcp_syncookies=1,重複上面測試,當 watch 'netstat -antp|grep SYN_RECV|wc -l' 等於16時,換一臺機器鏈接server發現此時鏈接成功。測試

#!/bin/sh initPort=10000
for ((i=1; i<=200; i ++)) do initPort=$[initPort+1] sendip -v -p  ipv4 -is 1.1.1.1 -p tcp  -ts $initPort -td 19090 -tfs -tots 1.1.1.2 sleep 0.5 done
相關文章
相關標籤/搜索