libnids中TCP重組中的主要函數process_tcp()分析


重點:這篇為轉載,作者在這塊分析的很好,雖然現在libnids已經更新到了1.24,但函數的大體流程還是未變,正文

 1 void process_tcp(u_char * data, int skblen)//傳入數據與其長度
 2 {
 3   struct ip *this_iphdr = (struct ip *)data;//ip與tcp結構體見后面說明
 4   struct tcphdr *this_tcphdr = (struct tcphdr *)(data + 4 * this_iphdr->ip_hl);
 5   //計算ip部分偏移指到TCP頭部
 6   int datalen, iplen;//數據部分長度,以及ip長度
 7   int from_client = 1;
 8   unsigned int tmp_ts;//時間戳
 9   struct tcp_stream *a_tcp;//一個TCP流的全部信息
10   struct half_stream *snd, *rcv;
11   //一個方向上的TCP流,TCP分為兩個方向上的,一個是客戶到服務端,一個是服務端到客戶
12 
13   ugly_iphdr = this_iphdr;
14   iplen = ntohs(this_iphdr->ip_len);
15   if ((unsigned)iplen < 4 * this_iphdr->ip_hl + sizeof(struct tcphdr)) {
16     nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
17                this_tcphdr);//指示的長度與實際的不相符,指出錯誤
18     return;
19   } // ktos sie bawi
20   
21   datalen = iplen - 4 * this_iphdr->ip_hl - 4 * this_tcphdr->th_off;
22  //tcp數據部分長度,去掉了TCP的頭部
23  //ip_hl表示ip頭部長度,th_off表示tcp頭部長度,datalen表示tcp數據部分長度
24  if (datalen < 0) {
25     nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
26                this_tcphdr);
27     return;
28   } // ktos sie bawi,數據部分小於0,發生錯誤,返回
29 
30   if ((this_iphdr->ip_src.s_addr | this_iphdr->ip_dst.s_addr) == 0) {
31     nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
32                this_tcphdr);
33     return;
34   }
35   if (!(this_tcphdr->th_flags & TH_ACK))//確認信息有效
36     detect_scan(this_iphdr);//如果是TCP中的ACK信息,檢測是否出現攻擊
37   if (!nids_params.n_tcp_streams) return;
38   if (my_tcp_check(this_tcphdr, iplen - 4 * this_iphdr->ip_hl,
39            this_iphdr->ip_src.s_addr, this_iphdr->ip_dst.s_addr)) {
40     nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_HDR, this_iphdr,
41                this_tcphdr);
42     return;
43   }//檢測數據包的有效性
44 #if 0
45   check_flags(this_iphdr, this_tcphdr);
46 //ECN
47 #endif
 1 //經過以上處,初步判斷tcp包正常,進行入隊操作,插入隊列前,先進行此包的狀態判斷,判斷此數據包處於何種狀態
 2   if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) {
 3   /*是三次握手的第一個包*/
 4   /*tcp里流不存在時:且tcp數據包里的(syn=1 && ack==0 && rst==0)時,添加一條tcp流*/
 5  /*tcp第一次握手*/
 6   if ((this_tcphdr->th_flags & TH_SYN) &&
 7     !(this_tcphdr->th_flags & TH_ACK) &&
 8     !(this_tcphdr->th_flags & TH_RST))
 9       add_new_tcp(this_tcphdr, this_iphdr);//發現新的TCP流,進行添加。
10 /*第一次握手完畢返回*/&nbsp;
  1 //在此處添加TCP流,但此處有隱患,對數據進行保存操作后,有可能數據沒釋放,實際應用中碰到中
  2  return;
  3   }
  4   if (from_client) {
  5     snd = &a_tcp->client;
  6     rcv = &a_tcp->server;
  7   }
  8   else {
  9     rcv = &a_tcp->client;
 10     snd = &a_tcp->server;
 11   }
 12 /**********************************************************************
 13 
 14                 三次握手的第二次握手
 15    
 16 ************************************************************************/
 17   
 18    /*tcp 三次握手, SYN ==1,ACK==1,tcp第二次握手(server -> client的同步響應)*/ 
 19 
 20 //來了一個SYN包
 21  if ((this_tcphdr->th_flags & TH_SYN)) {
 22 //syn包是用來建立新連接的,所以,要么來自客戶端且沒標志(前面處理了),要么來自服務端且加ACK標志
 23     //所以這里只能來自服務器,檢查服務器狀態是否正常,不正常的話果斷忽略這個包
 24  if (from_client || a_tcp->client.state != TCP_SYN_SENT ||
 25       a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK))
 26       return;
 27 /*第二次回應包的ACK 值為第一個包的序列號+1,在初始化的時候已經加一*/ 
 28 //忽略流水號錯誤的包
 29  if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack))
 30       return;
 31 
 32 /*第二個包服務端賦值*/
 33     /*a_tcp 中服務端賦值,*/
 34 //tcp流中有2個方向上的數據,此事可以給一個方向上的一些數據賦值
 35  a_tcp->server.state = TCP_SYN_RECV; 
 36 a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1; 
 37 a_tcp->server.first_data_seq = a_tcp->server.seq; 
 38 a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack); 
 39 a_tcp->server.window = ntohs(this_tcphdr->th_win);
 40 
 41   /*對於tcp 選項的賦值*/
 42   //初始化客戶端和服務器的時間截 
 43 
 44 
 45  if (a_tcp->client.ts_on) 
 46  { 
 47   a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts);
 48   if (!a_tcp->server.ts_on)
 49     a_tcp->client.ts_on = 0; 
 50   } else 
 51   a_tcp->server.ts_on = 0;//初始化窗口大小
 52   if (a_tcp->client.wscale_on) 
 53   { 
 54     a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale);
 55     if (!a_tcp->server.wscale_on)
 56    &nbsp;{
 57     a_tcp->client.wscale_on = 0;
 58     a_tcp->client.wscale = 1;
 59     a_tcp->server.wscale = 1;
 60     } 
 61   } 
 62   else 
 63    { 
 64     a_tcp->server.wscale_on = 0; 
 65     a_tcp->server.wscale = 1; 
 66    } 
 67 /*第二次握手完畢,返回*/ return; }
 68 /*
 69                 (如果有數據存在或者序列號不等於確認號的)並且
 70 
 71         序列號在窗口之外
 72         已經確認過的序號
 73 
 74    */
 75  if ( ! ( !datalen && ntohl(this_tcphdr->th_seq) == rcv->ack_seq ) && 
 76     ( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq + rcv->window*rcv->wscale) ||
 77       &nbsp;before(ntohl(this_tcphdr->th_seq) + datalen, rcv->ack_seq) ) ) 
 78       return;/*發送th_rst 重新開啟一個連接*/
 79 //如果是rst包,ok,關閉連接
 80   //將現有數據推給注冊的回調方,然后銷毀這個會話。 if ((this_tcphdr->th_flags & TH_RST)) {
 81 /*是tcp 數據*/ 
 82  if (a_tcp->nids_state == NIDS_DATA) { struct lurker_node *i; a_tcp->nids_state = NIDS_RESET;
 83 //下面回調所有的鈎子
 84  for (i = a_tcp->listeners; i; i = i->next)
 85    (i->item) (a_tcp, &i->data); 
 86     } 
 87     free_tcp(a_tcp); 
 88     return; 
 89    }
 90   /* PAWS check */
 91   /* PAWS(防止重復報文)check 檢查時間戳*/
 92 &nbsp;if (rcv->ts_on && get_ts(this_tcphdr, &tmp_ts) && before(tmp_ts, snd->curr_ts)) 
 93   return;
 94 &nbsp;/**********************************************************************
 95                         第三次握手包
 96 
 97         **********************************************************************
 98     */
 99   
100       /*
101     
102 
103       從client --> server的包
104 
105        是從三次握手的第三個包分析開始的,進行一部分數據分析,和初始化
106        連接狀態
107 
108       */ 
109 if ((this_tcphdr->th_flags & TH_ACK)) { //如果是從客戶端來的,且兩邊都在第二次握手的狀態上
110 if (from_client && a_tcp->client.state == TCP_SYN_SENT &&a_tcp->server.state == TCP_SYN_RECV) 
111   {//在此情況下,流水號又對得上,好的,這個包是第三次握手包,連接建立成功
112 if (ntohl(this_tcphdr->th_ack) == a_tcp->server.seq) 
113   {a_tcp->client.state = TCP_ESTABLISHED;
114   //更新客戶端狀態
115   a_tcp->client.ack_seq = ntohl(this_tcphdr->th_ack);
116   //更新ack序號
117     { 
118   struct proc_node *i; 
119   struct lurker_node *j; 
120   void *data; 
121   a_tcp->server.state = TCP_ESTABLISHED; 
122   a_tcp->nids_state = NIDS_JUST_EST;
123       /*開始全雙工傳輸,client server 連接已經建立起來了*/
124   
125       /*三次握手tcp ip 連接建立*/
126  for (i = tcp_procs; i; i = i->next) 
127    {&nbsp;//此處根據調用者的設定來判斷哪些數據需要在回調時返回
  1   char whatto = 0; 
  2 char cc = a_tcp->client.collect; 
  3 char sc = a_tcp->server.collect; 
  4 char ccu = a_tcp->client.collect_urg; 
  5 char scu = a_tcp->server.collect_urg;        /*進入回調函數處理*/
  6   
  7         /*
  8 
  9             如果在相應端口出現
 10 
 11         client.collect ++ ;
 12 
 13         測審計次數據
 14         對應用來說tcp 連接已經建立
 15 
 16        */ 
 17 (i->item) (a_tcp, &data); 
 18  if (cc < a_tcp->client.collect)
 19 &nbsp;whatto |= COLLECT_cc; 
 20 if (ccu < a_tcp->client.collect_urg) 
 21 whatto |= COLLECT_ccu; 
 22 if (sc < a_tcp->server.collect) 
 23 whatto |= COLLECT_sc; 
 24 if (scu < a_tcp->server.collect_urg) 
 25 whatto |= COLLECT_scu; 
 26 if (nids_params.one_loop_less) 
 27 { if (a_tcp->client.collect >=2) 
 28 { 
 29 a_tcp->client.collect=cc; 
 30 whatto&=~COLLECT_cc;
 31 &nbsp;} 
 32 if (a_tcp->server.collect >=2 ) 
 33 { 
 34 a_tcp->server.collect=sc;
 35 &nbsp;whatto&=~COLLECT_sc; 
 36 } 
 37 }
 38        /*加入監聽隊列,開始數據接收*/ 
 39 if (whatto) 
 40 {
 41 &nbsp;j = mknew(struct lurker_node);
 42 &nbsp;j->item = i->item; 
 43 j->data = data; 
 44 j->whatto = whatto; 
 45 j->next = a_tcp->listeners; 
 46 a_tcp->listeners = j;
 47 }
 48 &nbsp;} 
 49 if (!a_tcp->listeners)
 50 &nbsp;{/*不存在監聽着*/ 
 51 free_tcp(a_tcp); 
 52 return; 
 53 } 
 54 a_tcp->nids_state = NIDS_DATA;
 55 } 
 56 } 
 57 //
 58 &nbsp;return;
 59 &nbsp;} 
 60 }
 61 /*
 62 ************************************************************
 63 
 64                 揮手過程
 65 
 66 *************************************************************
 67 
 68 */
 69   
 70 /*數據結束的包的判斷*/
 71  if ((this_tcphdr->th_flags & TH_ACK)) {
 72 /* 從數據傳輸過程不斷更新服務器客戶端的ack_seq
 73     一直到接收到fin 包,數據傳輸結束
 74 
 75 */ 
 76 //先調用handle_ack更新ack序號
 77  handle_ack(snd, ntohl(this_tcphdr->th_ack));
 78 //更新狀態,回調告知連接關閉,然后釋放連接
 79  if (rcv->state == FIN_SENT) 
 80 rcv->state = FIN_CONFIRMED; 
 81 if (rcv->state == FIN_CONFIRMED && snd->state == FIN_CONFIRMED
 82 &nbsp;{ 
 83 struct lurker_node *i; 
 84 a_tcp->nids_state = NIDS_CLOSE; 
 85 for (i = a_tcp->listeners; i; i = i->next)
 86 (i->item) (a_tcp, &i->data); 
 87 free_tcp(a_tcp);
 88 &nbsp;return;
 89 &nbsp;} 
 90 }
 91 /*
 92 
 93 *************************************************************
 94                         數據處理過程
 95 *************************************************************
 96 
 97  */ 
 98 
 99  if (datalen + (this_tcphdr->th_flags & TH_FIN) > 0) /*
100           
101     a_tcp -----a_tcp 客戶端連接包
102     this_tcphdr tcp 包頭
103     snd-----發送包
104     rcv -----接收包
105 
106     (char *) (this_tcphdr) + 4 * this_tcphdr->th_off -----數據包內容
107     datalen---------數據包長度
108       
109 
110 */
111 //就將數據更新到接收方緩沖區 
112 tcp_queue(a_tcp, this_tcphdr, snd, rcv, (char *) (this_tcphdr) + 4 * this_tcphdr->th_off, datalen, skblen);
113 //更新窗口大小
114  snd->window = ntohs(this_tcphdr->th_win);
115 //如果緩存溢出(說明出了問題),果斷釋放連接
116  if (rcv->rmem_alloc > 65535) prune_queue(rcv, this_tcphdr); if (!a_tcp->listeners) free_tcp(a_tcp);}

附上tcphdr結構體的定義
struct tcphdr {
guint16 source;
guint16 dest;
guint32 seq;
guint32 ack_seq;
guint16 flags;
#define TH_FIN    0x01
#define TH_SYN    0x02
#define TH_RST    0x04
#define TH_PUSH   0x08
#define TH_ACK    0x10
#define TH_URG    0x20
guint16 window;
guint16 check;
guint16 urg_ptr;
};

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM