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


環境:centos7.4 內核版本3.10

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

為了測試上述結論,首先將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報文

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的值。

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時,計算過程如下:

    • 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM