Linux Kernel(2.6)の実装に関するメモ書き

listen backlog 【3.6】


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のサイズ

syn backlogのサイズはbacklogとnet.ipv4.tcp_max_syn_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()で行っている)。

表1 syn backlogサイズ計算例(tcp_max_syn_backlog = 400の場合)

backlogサイズsyn backlogサイズ
128 256
200 256
256 512
512 512(*1)

(*1) backlog(512)はtcp_max_syn_backlog(400)より大きいので、400を切り上げた512がsyn backlogのサイズになる。

 

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サイズに基づいて決まるため、net.ipv4.tcp_max_syn_backlogを大きくするだけでなく、backlog自体が大きくなるように(b),(c)も行う必要がある。

syn backlogにSYN_RECVがいくつまでたまるか、およびあふれた時の動作は、net.ipv4.tcp_syncookiesの値によって異なる。

 

4-1. SYN_RECVがいくつたまるか(net.ipv4.tcp_syncookies = 0の場合)

net.ipv4.tcp_syncookies = 0の場合、SYN_RECVは以下のいずれかのうち、小さい方の数まで登録できる。

  • syn backlogのサイズまで
  • net.ipv4.tcp_max_syn_backlogの3/4まで

これを越えると、新たにSYN_RECVは登録せず廃棄する。このため、新たにTCP接続を確立できない。

計算例)

  • backlog=512, tcp_max_syn_backlog=512の場合

syn backlogのサイズは1024、tcp_max_syn_backlogの4分の3は384なので、SYN_RECVは384まで登録される。

  • backlog=128, tcp_max_syn_backlog=512の場合

syn backlogのサイズは256、tcp_max_syn_backlogの4分の3は384なので、SYN_RECVは256まで登録される。

net.ipv4.tcp_max_syn_backlogを大きくしても、net.core.somaxconnが小さいと、backlogも小さく切り詰められ、syn backlogのサイズも小さくなるので、SYN_RECVの最大登録数が思ったように増えないことになる。このため、SYN_RECVの最大登録数を増やそうと思ったら、4.節の(a)〜(c)を合わせて行う必要がある。

 

4-2. SYN_RECVがいくつたまるか(net.ipv4.tcp_syncookies = 1の場合)

net.ipv4.tcp_syncookies = 1の場合、SYN_RECVはsyn backlogのサイズまで登録される。

SYN_RECVがsyn backlogのサイズを越えると、SYN Flood攻撃と判断し、SYN cookiesの動作が始まる。

 

5. SYN_RECVキューイングに関連するソース

SYN_RECVのキューイング/廃棄の処理はtcp_ipv4.c::tcp_v4_conn_request()で行っている。

 

syn backlogのキューフルチェック

	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;
	}

 

net.ipv4.tcp_syncookies = 0時のtcp_max_syn_backlog 4分の3チェック

		else if (!sysctl_tcp_syncookies &&
			 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
			  (sysctl_max_syn_backlog >> 2)) &&
			 !tcp_peer_is_proven(req, dst, false)) {
			/* Without syncookies last quarter of
			 * backlog is filled with destinations,
			 * proven to be alive.
			 * It means that we continue to communicate
			 * to destinations, already remembered
			 * to the moment of synflood.
			 */
			LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"),
				       &saddr, ntohs(tcp_hdr(skb)->source));
			goto drop_and_release;
		}

 


最終更新 2015/04/25 06:26:16 - kztomita
(2015/04/14 23:22:48 作成)
添付ファイル
backlog.png - kztomita


リンク
最近更新したページ
検索