隨手記之Linux內核SYN flooding警告信息
前言
最近線上服務器,dmesg會給出一些警告信息:
possible SYN flooding on port 8080. Sending cookies.
初看以為是受到DOS拒絕性攻擊,但仔細一分析,一天量也就是在1000多條左右,感覺上屬于正常可接受范圍。
下面需要找出來源,以及原因,以下內容基于Linux 2.6.18內核。
警告輸出源頭
net/ipv4/Tcp_ipv4.c:
#ifdef CONFIG_SYN_COOKIES
static void syn_flood_warning(struct sk_buff *skb)
{
static unsigned long warntime; // 第一次加載初始化為零,后續(xù)warntime = jiffies
if (time_after(jiffies, (warntime + HZ * 60))) {
warntime = jiffies;
printk(KERN_INFO
"possible SYN flooding on port %d. Sending cookies.\n",
ntohs(skb->h.th->dest));
}
}
#endif
很顯然,CONFIG_SYN_COOKIES在Linux系統(tǒng)編譯時,已被設置true。
time_after宏定義:
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
兩個無符號的時間比較,確定先后順序。
jiffies真身:
# define jiffies raid6_jiffies()
#define HZ 1000
......
static inline uint32_t raid6_jiffies(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + tv.tv_usec/1000; // 秒*1000 + 微秒/1000
}
回過頭來,再看看syn_flood_warning函數(shù):
static void syn_flood_warning(struct sk_buff *skb)
{
static unsigned long warntime; // 第一次加載初始化為零,后續(xù)warntime = jiffies
if (time_after(jiffies, (warntime + HZ * 60))) {
warntime = jiffies;
printk(KERN_INFO
"possible SYN flooding on port %d. Sending cookies.\n",
ntohs(skb->h.th->dest));
}
}
warntime為static類型,第一次調用時被初始化為零,下次調用就是上次的jiffies值了,前后間隔值超過HZ*60就不會輸出警告信息了。
有關time_after和jiffies,分享幾篇文章:
http://wenku.baidu.com/view/c75658d480eb6294dd886c4e.html
警告輸出需要滿足的條件
注意觀察want_cookie=1時的條件。
net/ipv4/Tcp_ipv4.c:
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct inet_request_sock *ireq;
struct tcp_options_received tmp_opt;
struct request_sock *req;
__u32 saddr = skb->nh.iph->saddr;
__u32 daddr = skb->nh.iph->daddr;
__u32 isn = TCP_SKB_CB(skb)->when; // when在tcp_v4_rcv()中會被置為0
struct dst_entry *dst = NULL;
#ifdef CONFIG_SYN_COOKIES
int want_cookie = 0;
#else
#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
#endif
/* Never answer to SYNs send to broadcast or multicast */
if (((struct rtable *)skb->dst)->rt_flags &
(RTCF_BROADCAST | RTCF_MULTICAST))
goto drop;
/* TW buckets are converted to open requests without
* limitations, they conserve resources and peer is
* evidently real one.
*/
// if(判斷半連接隊列已滿 && !0)
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
#ifdef CONFIG_SYN_COOKIES
if (sysctl_tcp_syncookies) { // net.ipv4.tcp_syncookies = 1
want_cookie = 1;
} else
#endif
goto drop;
}
/* Accept backlog is full. If we have already queued enough
* of warm entries in syn queue, drop request. It is better than
* clogging syn queue with openreqs with exponentially increasing
* timeout.
*/
// if(連接隊列是否已滿 && 半連接隊列中還有未重傳ACK半連接數(shù)字 > 1)
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
goto drop;
......
tcp_openreq_init(req, &tmp_opt, skb);
ireq = inet_rsk(req);
ireq->loc_addr = daddr;
ireq->rmt_addr = saddr;
ireq->opt = tcp_v4_save_options(sk, skb);
if (!want_cookie)
TCP_ECN_create_request(req, skb->h.th);
if (want_cookie) { // 半連接隊列已滿會觸發(fā)
#ifdef CONFIG_SYN_COOKIES
syn_flood_warning(skb);
#endif
isn = cookie_v4_init_sequence(sk, skb, &req->mss);
} else if (!isn) {
......
}
/* Kill the following clause, if you dislike this way. */
// net.ipv4.tcp_syncookies未設置情況下,sysctl_max_syn_backlog發(fā)生的作用
else if (!sysctl_tcp_syncookies &&
(sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
(sysctl_max_syn_backlog >> 2)) &&
(!peer || !peer->tcp_ts_stamp) &&
(!dst || !dst_metric(dst, RTAX_RTT))) {
/* 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 "TCP: drop open "
"request from %u.%u.%u.%u/%u\n",
NIPQUAD(saddr),
ntohs(skb->h.th->source));
dst_release(dst);
goto drop_and_free;
}
isn = tcp_v4_init_sequence(sk, skb);
}
tcp_rsk(req)->snt_isn = isn;
if (tcp_v4_send_synack(sk, req, dst))
goto drop_and_free;
if (want_cookie) {
reqsk_free(req);
} else {
inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
}
return 0;
drop_and_free:
reqsk_free(req);
drop:
return 0;
}
小結
總之,如系統(tǒng)出現(xiàn):
possible SYN flooding on port 8080. Sending cookies.
若量不大,是在提醒你需要關心一下sysctl_max_syn_backlog其值是否過低:
sysctl -a | grep 'max_syn_backlog'
不妨成倍增加一下
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sysctl -p
若進程無法做到重新加載,那就需要重啟應用,以適應新的內核參數(shù)。進而持續(xù)觀察一段時間。
貌似tcp_max_syn_backlog參數(shù)其完整作用域還沒有理解完整,下次有時間再寫吧。
posted on 2014-08-06 21:57 nieyong 閱讀(6801) 評論(5) 編輯 收藏 所屬分類: Socket