libNids TCP 分析

1. 使用場景

在一大流量網絡中心旁路抓包,不能完全排除亂序或丟包的可能

2. Review代碼

2.1 窗口檢驗部分代碼

  if (
    ! (  !datalen && ntohl(this_tcphdr->th_seq) == rcv->ack_seq  )
    && /* zero window handle */
    ( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq + rcv->window*rcv->wscale) ||
          before(ntohl(this_tcphdr->th_seq) + datalen, rcv->ack_seq)  
        )
      ) {
      return;
  }

上面的這串代碼有很大問題,如果TCP正常交互可能會沒太大的問題,但一旦有異常就會造成重組後的流不完整,甚至無法重組。

2.2 四次揮手部分代碼

  if ((this_tcphdr->th_flags & TH_ACK)) {
    handle_ack(snd, ntohl(this_tcphdr->th_ack));
    if (rcv->state == FIN_SENT)
      rcv->state = FIN_CONFIRMED;
    if ((rcv->state == FIN_CONFIRMED && snd->state == FIN_CONFIRMED) ||
        (rcv->state == FIN_CONFIRMED && snd->state == TCP_CLOSING)) {
      struct lurker_node *i;

      a_tcp->nids_state = NIDS_CLOSE;
      for (i = a_tcp->listeners; i; i = i->next)
          (i->item) (a_tcp, &i->data);
      nids_free_tcp_stream(tcp, a_tcp);
      return;
    }
  }

上面這部分代碼是處理 TCP關閉的,需要四次正確揮手才能走到這個邏輯裏,如果在一方出現異常,會在他處將其中的狀態置爲 TCP_CLOSING 所以在這還需要加入這個判斷。

還有個問題,Android 系統部分APP使用的是三次揮手,此時還需在process_tcp 後面對三次揮手的進行判斷,一時出現三次揮手即可關閉TCP,無需等待最後一個ack

2.2 內存增長

在TCP會造成內存快速增長的原因大致如下
* 如有丟包情況造成大量緩存包,如遲遲未補上所需報文將會愈演愈烈
* 上層數據要對 IP 數據包進行檢驗,看是否有IP分片,如果你的業務是基於TCP重組後的數據的話,請一定要做IP分片對系統影響的測試,否則一條TCP流就會被丟棄,64K的緩衝數據也會造成內存增加
* TCP 本身具有結點池,但其本身的池會按照分配的時間進行老化,建議在每個TCP流來新包的時候更新下順序,只需要將當前結點取出放置在最前端即可(TCP結點爲雙向鏈表,效率不是問題)強烈建議

3. 總結

先寫這麼多,這裏還有好多需要待完善,關鍵要看你的運用場景,對TCP重組有多大的要求,是否允許丟包等等。在現行情況下,技術是爲業務服務的,所以一定想清你的業務需要怎樣的TCP流。

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