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