listen backlog 【3.6】
Rev.13を表示中。最新版はこちら。
1. 概要
listen()時に指定するbacklogに関するメモ。
2. backlogとsyn backlog
listen()システムコールでLISTEN状態にあるソケットはbacklogというキューを持つ。backlogにはクライアントからのTCP接続要求が確立(ESTABLISH状態)し、まだaccept()されていない接続が並ぶ。
Listenソケットはbacklog以外にもTCP接続中(SYN_RECV状態)の接続を格納しておくキューがある。各種ドキュメントではキューと呼んでいるが、実際にはハッシュテーブルで実装されている。ここではsyn backlogと呼ぶ。
backlogのキューはinet_csk(sk)->icsk_accept_queueの.rskq_accept_headと.rskq_accept_tailで管理され、syn backlogのハッシュはinet_csk(sk)->icsk_accept_queue.listen_opt->syn_tableで管理される(図1)。
図1 Listenソケットとbacklog
3. backlogサイズ
backlogのキュー長はlisten()時に指定されるbacklog引数の値に設定される。ただし、指定値がsysctlのnet.core.somaxconnより大きかった場合は、net.core.somaxconnの値に切り詰められる。
4. syn backlogのサイズ(net.ipv4.tcp_syncookies = 0の場合)
syn backlogにSYN_RECVがいくつたまるかはnet.ipv4.tcp_syncookiesの値によって変わる。
net.ipv4.tcp_syncookies = 0の場合、SYN_RECVはnet.ipv4.tcp_max_syn_backlogの3/4まで登録される。これを越えると新たにSYN_RECVは登録せず廃棄する。このため、新たにTCP接続を確立できない。
5. syn backlogのサイズ(net.ipv4.tcp_syncookies = 1)
net.ipv4.tcp_syncookies = 1の場合、syn backlogのサイズはbacklogサイズに基づいて決められる。
syn backlogのサイズはbacklog値を8〜net.ipv4.tcp_max_syn_backlogの範囲に収めた後、一つ上の2の階乗の値に切り上げた値になる。例えば、backlog長が200ならsyn backlogサイズは256、backlog長が256ならsyn backlogサイズは512となる(syn backlogの初期化処理はreqsk_queue_alloc()で行っている)。
SYN_RECVがsyn backlogのサイズを越えると、SYN Flood攻撃と判断しSYN cookiesの動作が始まる。
SYN Flood攻撃への耐性をあげようとsyn backlogのサイズを大きくしようとする場合は、以下の点に注意する。
(a) net.ipv4.tcp_max_syn_backlogを大きくする
(b) listen()で指定するbacklog値を大きくする(apacheならListenBackLogディレクティブで指定できる)
(c) backlogの値自体はnet.core.somaxconnに切り詰められるため、net.core.somaxconnの方も大きくしておく。
syn backlogの最大サイズはbacklogサイズに基づいて決まるため(2. backlogとsyn backlog を参照)、net.ipv4.tcp_max_syn_backlogを大きくするだけでなく、backlog自体が大きくなるように(b),(c)も行う必要がある。