Linux tcp之sync cookie

1、常規的tcp連接裏,server在收到client的sync報文後就會分配request_sock,並將其放到半連接隊列裏;如果server受到惡意攻擊,攻擊方不斷的發sync包,發完就退出,這樣server端的半連接隊列很快就會被填滿,導致無法進行正常的tcp sync請求,這也是常見的sync flood攻擊。

針對這種問題,新增了sync cookie功能,爲了支持該功能,內核新增了一個tcp_syncookies參數,先看下內核文檔對該參數的描述:

tcp_syncookies - BOOLEAN
        Only valid when the kernel was compiled with CONFIG_SYN_COOKIES
        Send out syncookies when the syn backlog queue of a socket
        overflows. This is to prevent against the common 'SYN flood attack'
        Default: 1

        Note, that syncookies is fallback facility.
        It MUST NOT be used to help highly loaded servers to stand
        against legal connection rate. If you see SYN flood warnings
        in your logs, but investigation shows that they occur
        because of overload with legal connections, you should tune
        another parameters until this warning disappear.
        See: tcp_max_syn_backlog, tcp_synack_retries, tcp_abort_on_overflow.

        syncookies seriously violate TCP protocol, do not allow
        to use TCP extensions, can result in serious degradation
        of some services (f.e. SMTP relaying), visible not by you,
        but your clients and relays, contacting you. While you see
        SYN flood warnings in logs not being really flooded, your server
        is seriously misconfigured.

        If you want to test which effects syncookies have to your
        network connections you can set this knob to 2 to enable
        unconditionally generation of syncookies.


從描述裏可以看到,這個參數是在syn backlog queue溢出時使用的,這裏的queue指的就是半連接隊列,這裏的隊列長度取決於listen系統調用的第二個參數(backlog長度)及系統參數/proc/sys/net/ipv4/tcp_max_syn_backlog,詳情看reqsk_queue_alloc實現。tcp_syncookies默認值爲1,即只有等sys queue溢出時才起作用,設定爲2表示強制使用sync cookie,0表示關閉sync cookie。

2、原理:

1)、server在收到sync包後,判斷是否需要使用sync cookie,如果需要使用,則server根據流的源/宿ip、源/宿端口、序列號以及mss值hash成一個cookie,然後作爲sync+ack報文的初始序列號發送給client,server本地不保存相關的request_sock信息;
2)、client收到sync+ack後,將序列號加1,然後返回ack給server;
3)、server收到ack後,先從半連接隊列裏找request_sock,如果找不到,則進行sync cookie判斷,判斷方法是:
   a)、將包的ack_seq序列號減1,減完1後的序列號值即爲server一開始初始化創建的cookie值; 
   b)、根據收到的ack包的源/宿ip、源/宿端口、及序列號減1重新hash一個cookie值,然後跟上一步得到的cookie比較,並得到mss值,則正常創建request_sock,然後更新相關信息,將sk->sk_state置爲ESTABLISHED狀態,request_sock保存到連接隊列裏。

3、server端實現:

1)、收到sync報文,分配sync cookie

tcp_v4_rcv
    tcp_v4_do_rcv
        tcp_v4_hnd_req
            tcp_rcv_state_process
                tcp_v4_conn_request
                    tcp_conn_request

int tcp_conn_request(struct request_sock_ops *rsk_ops,
					const struct tcp_request_sock_ops *af_ops,
					struct sock *sk, struct sk_buff *skb)
{
	/* TW buckets are converted to open requests without
	* limitations, they conserve resources and peer is
	* evidently real one.
	*/
	//判斷是否強制使用sync cookie,或者sync queue是否已經溢出
	//want_cookie表示需要使用sync cookie功能
	if ((sysctl_tcp_syncookies == 2 ||
		inet_csk_reqsk_queue_is_full(sk)) && !isn) {
		want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name);
		if (!want_cookie)
			goto drop;
		}

	//如果需要使用sync cookie,則根據流的信息hash一個初始序列號
	if (want_cookie) {
		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
		req->cookie_ts = tmp_opt.tstamp_ok;
		if (!tmp_opt.tstamp_ok)
			inet_rsk(req)->ecn_ok = 0;
	}
						
	//將hash生成的序列號作爲sync+ack包的初始序列號
	tcp_rsk(req)->snt_isn = isn;
				
	if (!fastopen) {
		//如果使用sync cookie,則不保存request_sock信息,直接釋放掉.
		if (err || want_cookie)
			goto drop_and_free;

		tcp_rsk(req)->listener = NULL;
		af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
	}

	return 0;
}

2)、server收到ack,分配requeset_sock

tcp_v4_rcv
    tcp_v4_do_rcv
        tcp_v4_hnd_req      

static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
	#ifdef CONFIG_SYN_COOKIES
	//收到client的ack時,找不到request_sock,檢查cookie值
	if (!th->syn)
		sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
	#endif
	return sk;
}	

            cookie_v4_check
                __cookie_v4_check

int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, u32 cookie)
{
	//先將序列號減1
	__u32 seq = ntohl(th->seq) - 1;
	//獲得mss id
	__u32 mssind = check_tcp_syn_cookie(cookie, iph->saddr, iph->daddr,
					th->source, th->dest, seq);
	//如果得到的mss在msstab範圍內,則認爲檢查通過,說明使用sync cookie有個限制;
	//就是mss的值只能固定msstab裏定義的那幾種
	return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}

                get_cookie_sock
                    tcp_v4_syn_recv_sock(這裏面新創一個request_sock,然後將狀態置爲SYNC_RECV)
                        inet_csk_reqsk_queue_add(將requeset_sock加到全連接隊列裏)

4、缺陷:

1)、使用sync cookie後,由於server在收到sync報文時不保存request_sock信息,所以有一些在sync裏協商的tcp option字段無法使用,比如WScale(窗口擴大因子)、sack等;
mss信息本來也是在sync裏協商的,因爲server在生成cookie時會帶上mss信息,等收到ack後再計算得到mss,所以mss信息可以保留下來;

2)、mss的類型只能固定幾種。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章