聶永的博客

          記錄工作/學習的點點滴滴。

          隨手記之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

          http://www.360doc.com/content/11/1201/09/1317564_168810003.shtml

           

          警告輸出需要滿足的條件

          注意觀察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

          評論

          # re: 隨手記之Linux內核SYN flooding警告信息 2014-08-07 09:06 金利鎖業(yè)

          謝謝博主分享,,,,,,  回復  更多評論   

          # re: 隨手記之Linux內核SYN flooding警告信息 2014-08-08 17:18 用戶體驗

          行家一出手就只有沒有,用戶體驗不錯.  回復  更多評論   

          # re: 隨手記之Linux內核SYN flooding警告信息 2014-08-09 11:28 金利鎖業(yè)

          支持博主分享,。  回復  更多評論   

          # re: 隨手記之Linux內核SYN flooding警告信息 2014-08-23 11:46 好鄰居官網(wǎng)

          謝謝指教了~感謝分享了!  回復  更多評論   

          # re: 隨手記之Linux內核SYN flooding警告信息 2014-08-25 09:39 喜歡研究的人類

          以前在
          http://www.copyright8.com/
          有介紹,現(xiàn)在怎么變成了讀后感的網(wǎng)站?我暈  回復  更多評論   

          公告

          所有文章皆為原創(chuàng),若轉載請標明出處,謝謝~

          新浪微博,歡迎關注:

          導航

          <2014年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          統(tǒng)計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 长宁区| 油尖旺区| 丁青县| 莱州市| 梅州市| 沾化县| 大同县| 安岳县| 土默特左旗| 昌邑市| 南华县| 隆化县| 都江堰市| 木里| 大港区| 呼和浩特市| 巩义市| 武平县| 乐平市| 朝阳市| 九江县| 平湖市| 伊金霍洛旗| 砀山县| 公主岭市| 蛟河市| 民和| 延庆县| 毕节市| 建瓯市| 黔南| 纳雍县| 金湖县| 剑河县| 广丰县| 临洮县| 平顺县| 崇义县| 沈丘县| 井研县| 云林县|