Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1256698
  • 博文数量: 177
  • 博客积分: 1528
  • 博客等级: 上尉
  • 技术积分: 1891
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-15 18:03
文章分类

全部博文(177)

文章存档

2020年(1)

2018年(19)

2017年(4)

2016年(21)

2015年(40)

2014年(13)

2013年(26)

2012年(16)

2011年(37)

我的朋友

分类: LINUX

2015-02-06 12:02:19

nids首先初始化:

点击(此处)折叠或打开

  1. int nids_init() 
  2. { 
  3.     if (nids_params.filename) { 
  4.     if ((desc = pcap_open_offline(nids_params.filename, 
  5.                       nids_errbuf)) == NULL) 
  6.         return 0; 
  7.     } else if (!open_live()) 
  8.     return 0; 
  9.   
  10.     if (nids_params.pcap_filter != NULL) { 
  11.     u_int mask = 0; 
  12.     struct bpf_program fcode; 
  13.   
  14.     if (pcap_compile(desc, &fcode, nids_params.pcap_filter, 1, mask) < 
  15.         0) return 0; 
  16.     if (pcap_setfilter(desc, &fcode) == -1) 
  17.         return 0; 
  18.     } 
  19.     switch ((linktype = pcap_datalink(desc))) { 
  20. #ifdef DLT_IEEE802_11 
  21. #ifdef DLT_PRISM_HEADER 
  22.     case DLT_PRISM_HEADER: 
  23. #endif 
  24.     case DLT_IEEE802_11: 
  25.     /* wireless, need to calculate offset per frame */ 
  26.     break; 
  27. #endif 
  28. #ifdef DLT_NULL 
  29.     case DLT_NULL: 
  30.         linkoffset = 4; 
  31.         break; 
  32. #endif 
  33.     case DLT_EN10MB: 
  34.     linkoffset = 14; 
  35.     break; 
  36.     case DLT_PPP: 
  37.     linkoffset = 4; 
  38.     break; 
  39.     /* Token Ring Support by vacuum@technotronic.com, thanks */ 
  40.     case DLT_IEEE802: 
  41.     linkoffset = 22; 
  42.     break; 
  43.   
  44.     case DLT_RAW: 
  45.     case DLT_SLIP: 
  46.     linkoffset = 0; 
  47.     break; 
  48. #define DLT_LINUX_SLL 113 
  49.     case DLT_LINUX_SLL: 
  50.     linkoffset = 16; 
  51.     break; 
  52. #ifdef DLT_FDDI 
  53.     case DLT_FDDI: 
  54.         linkoffset = 21; 
  55.         break; 
  56. #endif 
  57. #ifdef DLT_PPP_SERIAL 
  58.     case DLT_PPP_SERIAL: 
  59.         linkoffset = 4; 
  60.         break; 
  61. #endif 
  62.     default: 
  63.     strcpy(nids_errbuf, "link type unknown"); 
  64.     return 0; 
  65.     } 
  66.     if (nids_params.dev_addon == -1) { 
  67.     if (linktype == DLT_EN10MB) 
  68.         nids_params.dev_addon = 16; 
  69.     else 
  70.         nids_params.dev_addon = 0; 
  71.     } 
  72.     if (nids_params.syslog == nids_syslog) 
  73.     openlog("libnids", 0, LOG_LOCAL0); 
  74.   
  75.     init_procs(); 
  76.     tcp_init(nids_params.n_tcp_streams); 
  77.     ip_frag_init(nids_params.n_hosts); 
  78.     scan_init(); 
  79.     return 1; 
  80. }

点击(此处)折叠或打开

  1. static void init_procs() 
  2. { 
  3.     ip_frag_procs = mknew(struct proc_node); 
  4.     ip_frag_procs->item = gen_ip_frag_proc; 
  5.     ip_frag_procs->next = 0; 
  6.     ip_procs = mknew(struct proc_node); 
  7.     ip_procs->item = gen_ip_proc; 
  8.     ip_procs->next = 0; 
  9.     tcp_procs = 0; 
  10.     udp_procs = 0; 
  11. }

点击(此处)折叠或打开

  1. int tcp_init(int size) 
  2. { 
  3.   int i; 
  4.   if (!size) return 0; 
  5.   tcp_stream_table_size = size; 
  6.   tcp_stream_table = malloc(tcp_stream_table_size * sizeof(char *)); 
  7.   if (!tcp_stream_table) 
  8.     nids_params.no_mem("tcp_init"); 
  9.   memset(tcp_stream_table, 0, tcp_stream_table_size * sizeof(char *)); 
  10.   max_stream = 3 * tcp_stream_table_size / 4; 
  11.   streams_pool = (struct tcp_stream *) malloc((max_stream + 1) * sizeof(struct tcp_stream)); 
  12.   if (!streams_pool) 
  13.     nids_params.no_mem("tcp_init"); 
  14.   for (= 0; i < max_stream; i++) 
  15.     streams_pool[i].next_free = &(streams_pool[+ 1]); 
  16.   streams_pool[max_stream].next_free = 0; 
  17.   free_streams = streams_pool; 
  18.   init_hash(); 
  19.   return 0; 
  20. }
哈希树初始化:

点击(此处)折叠或打开

  1. void init_hash ()
  2. {
  3.   int i, n, j;
  4.   int p[12];
  5.   getrnd ();
  6.   for (i = 0; i < 12; i++)
  7.     p[i] = i;
  8.   for (i = 0; i < 12; i++)
  9.     {
  10.       n = perm[i] % (12 - i);
  11.       perm[i] = p[n];
  12.       for (j = 0; j < 11 - n; j++)
  13.     p[n + j] = p[n + j + 1];
  14.     }
  15. }

点击(此处)折叠或打开

  1. static u_char xor[12];
  2. static u_char perm[12];
  3. static void
  4. getrnd ()
  5. {
  6.   struct timeval s;
  7.   u_int *ptr;
  8.   int fd = open ("/dev/urandom", O_RDONLY);
  9.   if (fd > 0)
  10.     {
  11.       read (fd, xor, 12);
  12.       read (fd, perm, 12);
  13.       close (fd);
  14.       return;
  15.     }
  16.   
  17.   gettimeofday (&s, 0);
  18.   srand (s.tv_usec);
  19.   ptr = (u_int *) xor;
  20.   *ptr = rand ();
  21.   *(ptr + 1) = rand ();
  22.   *(ptr + 2) = rand ();
  23.   ptr = (u_int *) perm;
  24.   *ptr = rand ();
  25.   *(ptr + 1) = rand ();
  26.   *(ptr + 2) = rand ();
  27.   
  28.   
  29. }

点击(此处)折叠或打开

  1. u_int
  2. mkhash (u_int src, u_short sport, u_int dest, u_short dport)
  3. {
  4.   u_int res = 0;
  5.   int i;
  6.   u_char data[12];
  7.   *(u_int *) (data) = src;
  8.   *(u_int *) (data + 4) = dest;
  9.   *(u_short *) (data + 8) = sport;
  10.   *(u_short *) (data + 10) = dport;
  11.   for (i = 0; i < 12; i++)
  12.     res = ( (res << 8) + (data[perm[i]] ^ xor[i])) % 0xff100f;
  13.   return res;
  14. }

以下是对哈希函数的说明,来自互联网

哈希表和哈希函数是大学数据结构中的课程,实际开发中我们经常用到Hashtable这种结构,当遇到键-值对存储,采用Hashtable比ArrayList查找的性能高。为什么呢?我们在享受高性能的同时,需要付出什么代价(这几天看红顶商人胡雪岩,经典台词:在你享受这之前,必须受别人吃不了的苦,忍受别人受不了的屈辱),那么使用Hashtable是否就是一桩无本万利的买卖呢?就此疑问,做以下分析,希望能抛砖引玉。
1)hash它为什么对于键-值查找性能高
学过数据结构的,都应该晓得,线性表和树中,记录在结构中的相对位置是随机的,记录和关键字之间不存在明确的关系,因此在查找记录的时候,需要进行一系列的关键字比较,这种查找方式建立在比较的基础之上,在java中(Array,ArrayList,List)这些集合结构采用了上面的存储方式。
比如,现在我们有一个班同学的数据,包括姓名,性别,年龄,学号等。假如数据有

姓名 性别 年龄 学号
张三 15 1
李四 14 2
王五 14 3


假如,我们按照姓名来查找,假设查找函数FindByName(stringname);
1)查找“张三”
只需在第一行匹配一次。
2)查找"王五"
   在第一行匹配,失败,
   在第二行匹配,失败,
   在第三行匹配,成功
上面两种情况,分别分析了最好的情况,和最坏的情况,那么平均查找次数应该为(1+3)/2=2次,即平均查找次数为(记录总数+1)的1/2。
尽管有一些优化的算法,可以使查找排序效率增高,但是复杂度会保持在log2n的范围之内。
如何更更快的进行查找呢?我们所期望的效果是一下子就定位到要找记录的位置之上,这时候时间复杂度为1,查找最快。如果我们事先为每条记录编一个序号,然后让他们按号入位,我们又知道按照什么规则对这些记录进行编号的话,如果我们再次查找某个记录的时候,只需要先通过规则计算出该记录的编号,然后根据编号,在记录的线性队列中,就可以轻易的找到记录了 。
注意,上述的描述包含了两个概念,一个是用于对学生进行编号的规则,在数据结构中,称之为哈希函数,另外一个是按照规则为学生排列的顺序结构,称之为哈希表。
仍以上面的学生为例,假设学号就是规则,老师手上有一个规则表,在排座位的时候也按照这个规则来排序,查找李四,首先该教师会根据规则判断出,李四的编号为2,就是在座位中的2号位置,直接走过去,“李四,哈哈,你小子,就是在这!”
看看大体流程:
  
从上面的图中,可以看出哈希表可以描述为两个筒子,一个筒子用来装记录的位置编号,另外一个筒子用来装记录,另外存在一套规则,用来表述记录与编号之间的联系。这个规则通常是如何制定的呢?
a)直接定址法:
   我在前一篇文章对GetHashCode()性能比较的问题中谈到,对于整形的数据GetHashCode()函数返回的就是整形本身,其实就是基于直接定址的方法,比如有一组0-100的数据,用来表示人的年龄
那么,采用直接定址的方法构成的哈希表为:

0 1 2 3 4 5
0岁 1岁 2岁 3岁 4岁 5岁
.....
这样的一种定址方式,简单方便,适用于元数据能够用数字表述或者原数据具有鲜明顺序关系的情形。
b)数字分析法:
 
 有这样一组数据,用于表述一些人的出生日期
75 10
75 12 10
75 02 14
分析一下,年和月的第一位数字基本相同,造成冲突的几率非常大,而后面三位差别比较大,所以采用后三位
c)平方取中法
 取关键字平方后的中间几位作为哈希地址
d) 折叠法:
 将关键字分割成位数相同的几部分,最后一部分位数可以不相同,然后去这几部分的叠加和(取出进位)作为哈希地址,比如有这样的数据20-1445-4547-3
可以
        5473
+      4454
+        201
=    10128
取出进位1,取0128为哈希地址
e)取余法
取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。H(key)=keyMOD p (p<=m)
f) 随机数法
 选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常用于关键字长度不等时采用此法。

总之,哈希函数的规则是:通过某种转换关系,使关键字适度的分散到指定大小的的顺序结构中。越分散,则以后查找的时间复杂度越小,空间复杂度越高。
2)使用hash,我们付出了什么?
hash是一种典型以空间换时间的算法,比如原来一个长度为100的数组,对其查找,只需要遍历且匹配相应记录即可,从空间复杂度上来看,假如数组存储的是byte类型数据,那么该数组占用100byte空间。现在我们采用hash算法,我们前面说的hash必须有一个规则,约束键与存储位置的关系,那么就需要一个固定长度的hash表,此时,仍然是100byte的数组,假设我们需要的100byte用来记录键与位置的关系,那么总的空间为200byte,而且用于记录规则的表大小会根据规则,大小可能是不定的.
注:hash表最突出的问题在于冲突,就是两个键值经过哈希函数计算出来的索引位置很可能相同,
注:之所以会简单得介绍了hash,是为了更好的学习lsh算法

解决冲突的主要方法
  虽然我们不希望发生冲突,但实际上发生冲突的可能性仍是存在的。当关键字值域远大于哈希表的长度,而且事先并不知道关键字的具体取值时。冲突就难免会发生。另外,当关键字的实际取值大于哈希表的长度时,而且表中已装满了记录,如果插入一个新记录,不仅发生冲突,而且还会发生溢出。因此,处理冲突和溢出是哈希技术中的两个重要问题。
1、开放定址法
    用开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的地址则表明表中无待查的关键字,即查找失败。
  注意:
 ①用开放定址法建立散列表时,建表前须将表中所有单元(更严格地说,是指单元中存储的关键字)置空。
 ②空单元的表示与具体的应用相关。
    按照形成探查序列的方法不同,可将开放定址法区分为线性探查法、线性补偿探测法、随机探测等。
(1)线性探查法(Linear Probing)
该方法的基本思想是:
    将散列表T[0..m-1]看成是一个循环向量,若初始探查的地址为d(即h(key)=d),则最长的探查序列为:
       d,d+l,d+2,…,m-1,0,1,…,d-1
    即:探查时从地址d开始,首先探查T[d],然后依次探查T[d+1],…,直到T[m-1],此后又循环到T[0],T[1],…,直到探查到T[d-1]为止。
探查过程终止于三种情况:
    (1)若当前探查的单元为空,则表示查找失败(若是插入则将key写入其中);
    (2)若当前探查的单元中含有key,则查找成功,但对于插入意味着失败;
    (3)若探查到T[d-1]时仍未发现空单元也未找到key,则无论是查找还是插入均意味着失败(此时表满)。
利用开放地址法的一般形式,线性探查法的探查序列为:
       hi=(h(key)+i)%m 0≤i≤m-1 //即di=i
用线性探测法处理冲突,思路清晰,算法简单,但存在下列缺点:
  ①处理溢出需另编程序。一般可另外设立一个溢出表,专门用来存放上述哈希表中放不下的记录。此溢出表最简单的结构是顺序表,查找方法可用顺序查找。
  ② 按上述算法建立起来的哈希表,删除工作非常困难。假如要从哈希表HT中删除一个记录,按理应将这个记录所在位置置为空,但我们不能这样做,而只能标上已被删除的标记,否则,将会影响以后的查找。
   ③线性探测法很容易产生堆聚现象。所谓堆聚现象,就是存入哈希表的记录在表中连成一片。按照线性探测法处理冲突,如果生成哈希地址的连续序列愈长( 即不同关键字值的哈希地址相邻在一起愈长 ),则当新的记录加入该表时,与这个序列发生冲突的可能性愈大。因此,哈希地址的较长连续序列比较短连续序列生长得快,这就意味着,一旦出现堆聚( 伴随着冲突 ) ,就将引起进一步的堆聚。

在nids_init()函数中,TCP初始化完成之后,进行ip包初始化,函数如下:

ip_frag_init(nids_params.n_hosts);//ip哈希表大小,默认256


点击(此处)折叠或打开

  1. int ip_frag_init(int n)
  2. {
  3.   struct timeval tv;
  4.     
  5.   gettimeofday(&tv, 0);
  6.   time0 = tv.tv_sec;
  7.   fragtable = (struct hostfrags **) malloc(n * sizeof(struct hostfrags *));
  8.   if (!fragtable)
  9.     nids_params.no_mem("ip_frag_init");
  10.   memset(fragtable, 0, n * sizeof(struct hostfrags *));
  11.   hash_size = n;
  12.   
  13.   return 0;
  14. }

timeval结构体表示时间:

struct timeval结构体在time.h中的定义为:
struct timeval
{
__time_t tv_sec;        /* Seconds. */
__suseconds_t tv_usec;    /* Microseconds. */
};
其中,tv_sec为Epoch到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。比如当前我写博文时的tv_sec为1244770435,tv_usec为442388,即当前时间距Epoch时间1244770435秒,442388微秒。需要注意的是,因为循环过程,新建结构体变量等过程需消耗部分时间,我们作下面的运算时会得到如下结果:

点击(此处)折叠或打开

  1. int i;
  2. for (i = 0; i < 4; ++i)
  3. {
  4. gettimeofday(&tv, NULL);
  5. printf("%d\t%d\n", tv.tv_usec, tv.tv_sec);
  6. sleep(1);
  7. }
442388    1244770435
443119    1244770436
443543    1244770437
444153    1244770438
前面为微秒数,后面为秒数,可以看出,在这个简单运算中,只能精确到小数点后面一到两位,或者可以看出,每进行一次循环,均需花费0.005秒的时间,用这个程序来作计时器显然是不行的,除非精确计算产生的代码消耗时间。

nids初始化中最后一个函数为:scan_init();
点击(此处)折叠或打开
  1. void scan_init()
  2. {
  3.   struct timeval tv;
  4.   
  5.   if (nids_params.scan_num_hosts > 0) //存储口哈希表大小,默认256<span style="font-size:18px;"></span>
  6.   {
  7.     gettimeofday(&tv, 0);
  8.     time0 = tv.tv_sec;
  9.     hashhost = (struct host **) malloc(sizeof(struct host *) * nids_params.scan_num_hosts);
  10.     if (!hashhost)
  11.       nids_params.no_mem("scan_init");
  12.     memset(hashhost, 0, sizeof(struct host *) * nids_params.scan_num_hosts);
  13.   }
  14. }

下面来看下run函数nids_run():
点击(此处)折叠或打开
  1. void nids_run()
  2. {
  3.     if (!desc) {
  4.     strcpy(nids_errbuf, "Libnids not initialized");
  5.     return;
  6.     }
  7.     pcap_loop(desc, -1, (pcap_handler) pcap_hand, 0);
  8.     clear_stream_buffers();
  9.     strcpy(nids_errbuf, "loop: ");
  10.     strncat(nids_errbuf, pcap_geterr(desc), sizeof(nids_errbuf) - 7);
  11.     pcap_close(desc);
  12. }

run函数调用pcap_loop()函数。此函数为libpcap中的函数,无限循环抓包,抓到的包交给回调函数处理。

回调函数处理流程如下:
点击(此处)折叠或打开

  1. static void pcap_hand(u_char * par, struct pcap_pkthdr *hdr, u_char * data)
  2. {
  3.     struct proc_node *i;
  4.     u_char *data_aligned;
  5. #ifdef DLT_IEEE802_11
  6.     unsigned short fc;
  7.     int linkoffset_tweaked_by_prism_code = 0;
  8. #endif
  9.     nids_last_pcap_header = hdr;
  10.     (void)par; /* warnings... */
  11.     switch (linktype) {
  12.     case DLT_EN10MB:
  13.     if (hdr->caplen < 14)
  14.         return;
  15.     /* Only handle IP packets and 802.1Q VLAN tagged packets below. */
  16.     if (data[12] == 8 && data[13] == 0) {
  17.         /* Regular ethernet */
  18.         linkoffset = 14;
  19.     } else if (data[12] == 0x81 && data[13] == 0) {
  20.         /* Skip 802.1Q VLAN and priority information */
  21.         linkoffset = 18;
  22.     } else
  23.         /* non-ip frame */
  24.         return;
  25.     break;
  26. #ifdef DLT_PRISM_HEADER
  27. #ifndef DLT_IEEE802_11
  28. #error DLT_PRISM_HEADER is defined, but DLT_IEEE802_11 is not ???
  29. #endif
  30.     case DLT_PRISM_HEADER:
  31.     linkoffset = 144; //sizeof(prism2_hdr);
  32.     linkoffset_tweaked_by_prism_code = 1;
  33.         //now let DLT_IEEE802_11 do the rest
  34. #endif
  35. #ifdef DLT_IEEE802_11
  36.     case DLT_IEEE802_11:
  37.     /* I don't know why frame control is always little endian, but it
  38.      * works for tcpdump, so who am I to complain? (wam)
  39.      */
  40.     if (!linkoffset_tweaked_by_prism_code)
  41.         linkoffset = 0;
  42.     fc = EXTRACT_LE_16BITS(data + linkoffset);
  43.     if (FC_TYPE(fc) != T_DATA || FC_WEP(fc)) {
  44.         return;
  45.     }
  46.     if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
  47.         /* a wireless distribution system packet will have another
  48.          * MAC addr in the frame
  49.          */
  50.         linkoffset += 30;
  51.     } else {
  52.         linkoffset += 24;
  53.     }
  54.     if (hdr->len < linkoffset + LLC_FRAME_SIZE)
  55.         return;
  56.     if (ETHERTYPE_IP !=
  57.         EXTRACT_16BITS(data + linkoffset + LLC_OFFSET_TO_TYPE_FIELD)) {
  58.         /* EAP, LEAP, and other 802.11 enhancements can be
  59.          * encapsulated within a data packet too. Look only at
  60.          * encapsulated IP packets (Type field of the LLC frame).
  61.          */
  62.         return;
  63.     }
  64.     linkoffset += LLC_FRAME_SIZE;
  65.     break;
  66. #endif
  67.     default:;
  68.     }
  69.     if (hdr->caplen < linkoffset)
  70.     return;
  71.   
  72. /*
  73. * sure, memcpy costs. But many EXTRACT_{SHORT, LONG} macros cost, too.
  74. * Anyway, libpcap tries to ensure proper layer 3 alignment (look for
  75. * handle->offset in pcap sources), so memcpy should not be called.
  76. */
  77. #ifdef LBL_ALIGN
  78.     if ((unsigned long) (data + linkoffset) & 0x3) {
  79.     data_aligned = alloca(hdr->caplen - linkoffset + 4);
  80.     data_aligned -= (unsigned long) data_aligned % 4;
  81.     memcpy(data_aligned, data + linkoffset, hdr->caplen - linkoffset);
  82.     } else
  83. #endif
  84.     data_aligned = data + linkoffset;
  85.     for (i = ip_frag_procs; i; i = i->next)
  86.     (i->item) (data_aligned, hdr->caplen - linkoffset);
  87. }

对于每一个包,都调用函数gen_ip_proc()进行处理,判断其类型,以便进行重组。



点击(此处)折叠或打开

  1. static void gen_ip_proc(u_char * data, int skblen)
  2. {
  3.     switch (((struct ip *) data)->ip_p) {
  4.     case IPPROTO_TCP:
  5.     process_tcp(data, skblen);
  6.     break;
  7.     case IPPROTO_UDP:
  8.     process_udp(data);
  9.     break;
  10.     case IPPROTO_ICMP:
  11.     if (nids_params.n_tcp_streams)
  12.         process_icmp(data);
  13.     break;
  14.     default:
  15.     break;
  16.     }
  17. }

首先分析一下抓包函数和回调函数之间的关系

函数名称:int pcap_loop(pcap_t * p,int cnt, pcap_handler callback, uchar * user);  

函数功能:捕获数据包,不会响应pcap_open_live()函数设置的超时时间  

参数说明:p 是由pcap_open_live()返回的所打的网卡的指针;

cnt用于设置所捕获数据包的个数;

pcap_handler 是与void packet_handler()使用的一个参数,即回调函数的名称;

user值一般为NULL  

pcap_loop原型是pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user)  

其中第一个参数是winpcap的句柄,第二个是指定捕获的数据包个数,如果为-1则无限循环捕获。第四个参数user是留给用户使用的。  

第三个是回调函数其原型如下:  pcap_callback(u_char* argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)  

其中参数pcap_content表示的捕获到的数据包的内容  

参数argument是从函数pcap_loop()传递过来的。注意:这里的参数就是指 pcap_loop中的 *user 参数  

参数pcap_pkthdr 表示捕获到的数据包基本信息,包括时间,长度等信息.  另

外:回调函数必须是全局函数或静态函数,其参数默认,比如pcap_loop()可以写成  

pcap_loop(pcap_handle,10,pcap_callback,NULL)不能往里面传递实参.  

-----------------------------------------------------------------------------------------------------------------  

pcap_loop和callback之间参数存在联系: 

 pcap_loop的最后一个参数user是留给用户使用的,当callback被调用的时候这个值会传递给callback的第一个参数(也叫user),

callback的最后一个参数p指向一块内存空间,这个空间中存放的就是pcap_loop抓到的数据包。

callback的第二个参数是一个结构体指针,该结构体定义如下:  


点击(此处)折叠或打开

  1. struct pcap_pkthdr
  2.   
  3. {  struct timeval ts; /* 时间戳 */  
  4.   
  5. bpf_u_int32 caplen; /* 已捕获部分的长度 */  
  6.   
  7. bpf_u_int32 len; /* 该包的脱机长度 */  
  8.   
  9. }; 


这个结构体是由pcap_loop自己填充的,用来取得一些关于数据包的信息  

所以,在callback函数当中只有第一个user指针是可以留给用户使用的,

如果你想给callback传递自己参数,那就只能通过pcap_loop的最后一个参数user来实现了

无限循环的抓包函数的回调函数调用了gen_ip_proc()函数,该函数通过判断类型进入到对应的重组阶段。下面开始分析TCP重组部分。

函数名:process_tcp(data, skblen)

代码很长,如下:

点击(此处)折叠或打开

  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

  48. //经过以上处,初步判断tcp包正常,进行入队操作,插入队列前,先进行此包的状态判断,判断此数据包处于何种状态
  49.   if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) {
  50.   /*是三次握手的第一个包*/
  51.   /*tcp里流不存在时:且tcp数据包里的(syn=1 && ack==0 && rst==0),添加一条tcp流*/
  52.  /*tcp第一次握手*/
  53.   if ((this_tcphdr->th_flags & TH_SYN) &&
  54.     !(this_tcphdr->th_flags & TH_ACK) &&
  55.     !(this_tcphdr->th_flags & TH_RST))
  56.       add_new_tcp(this_tcphdr, this_iphdr);//发现新的TCP流,进行添加。
  57. /*第一次握手完毕返回*/

  58. //在此处添加TCP流,但此处有隐患,对数据进行保存操作后,有可能数据没释放,实际应用中碰到中
  59.  return;
  60.   }
  61.   if (from_client) {
  62.     snd = &a_tcp->client;
  63.     rcv = &a_tcp->server;
  64.   }
  65.   else {
  66.     rcv = &a_tcp->client;
  67.     snd = &a_tcp->server;
  68.   }
  69. /**********************************************************************
  70.  
  71.                 三次握手的第二次握手
  72.     
  73. ************************************************************************/
  74.     
  75.    /*tcp 三次握手, SYN ==1,ACK==1,tcp第二次握手(server -> client的同步响应)*/
  76.   
  77. //来了一个SYN包
  78.  if ((this_tcphdr->th_flags & TH_SYN)) {
  79. //syn包是用来建立新连接的,所以,要么来自客户端且没标志(前面处理了),要么来自服务端且加ACK标志
  80.     //所以这里只能来自服务器,检查服务器状态是否正常,不正常的话果断忽略这个包
  81.  if (from_client || a_tcp->client.state != TCP_SYN_SENT ||
  82.       a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK))
  83.       return;
  84. /*第二次回应包的ACK 值为第一个包的序列号+1,在初始化的时候已经加一*/
  85. //忽略流水号错误的包
  86.  if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack))
  87.       return;
  88.   
  89. /*第二个包服务端赋值*/
  90.     /*a_tcp 中服务端赋值,*/
  91. //tcp流中有2个方向上的数据,此事可以给一个方向上的一些数据赋值
  92.  a_tcp->server.state = TCP_SYN_RECV;
  93. a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1;
  94. a_tcp->server.first_data_seq = a_tcp->server.seq;
  95. a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack);
  96. a_tcp->server.window = ntohs(this_tcphdr->th_win);
  97.   
  98.   /*对于tcp 选项的赋值*/
  99.   //初始化客户端和服务器的时间截
  100.   
  101.   
  102.  if (a_tcp->client.ts_on)
  103.  {
  104.   a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts);
  105.   if (!a_tcp->server.ts_on)
  106.     a_tcp->client.ts_on = 0;
  107.   } else
  108.   a_tcp->server.ts_on = 0;//初始化窗口大小
  109.   if (a_tcp->client.wscale_on)
  110.   {
  111.     a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale);
  112.     if (!a_tcp->server.wscale_on)
  113.     {
  114.     a_tcp->client.wscale_on = 0;
  115.     a_tcp->client.wscale = 1;
  116.     a_tcp->server.wscale = 1;
  117.     }
  118.   }
  119.   else
  120.    {
  121.     a_tcp->server.wscale_on = 0;
  122.     a_tcp->server.wscale = 1;
  123.    }
  124. /*第二次握手完毕,返回*/ return; }
  125. /*
  126.                 (如果有数据存在或者序列号不等于确认号的)并且
  127.  
  128.         序列号在窗口之外
  129.         已经确认过的序号
  130.  
  131.    */
  132.  if ( ! ( !datalen && ntohl(this_tcphdr->th_seq) == rcv->ack_seq ) &&
  133.     ( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq + rcv->window*rcv->wscale) ||
  134.        before(ntohl(this_tcphdr->th_seq) + datalen, rcv->ack_seq) ) )
  135.       return;/*发送th_rst 重新开启一个连接*/
  136. //如果是rst包,ok,关闭连接
  137.   //将现有数据推给注册的回调方,然后销毁这个会话。 if ((this_tcphdr->th_flags & TH_RST)) {
  138. /*是tcp 数据*/
  139.  if (a_tcp->nids_state == NIDS_DATA) { struct lurker_node *i; a_tcp->nids_state = NIDS_RESET;
  140. //下面回调所有的钩子
  141.  for (i = a_tcp->listeners; i; i = i->next)
  142.    (i->item) (a_tcp, &i->data);
  143.     }
  144.     free_tcp(a_tcp);
  145.     return;
  146.    }
  147.   /* PAWS check */
  148.   /* PAWS(防止重复报文)check 检查时间戳*/
  149.  if (rcv->ts_on && get_ts(this_tcphdr, &tmp_ts) && before(tmp_ts, snd->curr_ts))
  150.   return;
  151.  /**********************************************************************
  152.                         第三次握手包
  153.  
  154.         **********************************************************************
  155.     */
  156.     
  157.       /*
  158.      
  159.  
  160.       从client --> server的包
  161.  
  162.        是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
  163.        连接状态
  164.  
  165.       */
  166. if ((this_tcphdr->th_flags & TH_ACK)) { //如果是从客户端来的,且两边都在第二次握手的状态上
  167. if (from_client && a_tcp->client.state == TCP_SYN_SENT &&a_tcp->server.state == TCP_SYN_RECV)
  168.   {//在此情况下,流水号又对得上,好的,这个包是第三次握手包,连接建立成功
  169. if (ntohl(this_tcphdr->th_ack) == a_tcp->server.seq)
  170.   {a_tcp->client.state = TCP_ESTABLISHED;
  171.   //更新客户端状态
  172.   a_tcp->client.ack_seq = ntohl(this_tcphdr->th_ack);
  173.   //更新ack序号
  174.     {
  175.   struct proc_node *i;
  176.   struct lurker_node *j;
  177.   void *data;
  178.   a_tcp->server.state = TCP_ESTABLISHED;
  179.   a_tcp->nids_state = NIDS_JUST_EST;
  180.       /*开始全双工传输,client server 连接已经建立起来了*/
  181.     
  182.       /*三次握手tcp ip 连接建立*/
  183.  for (i = tcp_procs; i; i = i->next)
  184.    { //此处根据调用者的设定来判断哪些数据需要在回调时返回

  185.   char whatto = 0;
  186. char cc = a_tcp->client.collect;
  187. char sc = a_tcp->server.collect;
  188. char ccu = a_tcp->client.collect_urg;
  189. char scu = a_tcp->server.collect_urg; /*进入回调函数处理*/
  190.     
  191.         /*
  192.  
  193.             如果在相应端口出现
  194.  
  195.         client.collect ++ ;
  196.  
  197.         测审计次数据
  198.         对应用来说tcp 连接已经建立
  199.  
  200.        */
  201. (i->item) (a_tcp, &data);
  202.  if (cc < a_tcp->client.collect)
  203.  whatto |= COLLECT_cc;
  204. if (ccu < a_tcp->client.collect_urg)
  205. whatto |= COLLECT_ccu;
  206. if (sc < a_tcp->server.collect)
  207. whatto |= COLLECT_sc;
  208. if (scu < a_tcp->server.collect_urg)
  209. whatto |= COLLECT_scu;
  210. if (nids_params.one_loop_less)
  211. { if (a_tcp->client.collect >=2)
  212. {
  213. a_tcp->client.collect=cc;
  214. whatto&=~COLLECT_cc;
  215.  }
  216. if (a_tcp->server.collect >=2 )
  217. {
  218. a_tcp->server.collect=sc;
  219.  whatto&=~COLLECT_sc;
  220. }
  221. }
  222.        /*加入监听队列,开始数据接收*/
  223. if (whatto)
  224. {
  225.  j = mknew(struct lurker_node);
  226.  j->item = i->item;
  227. j->data = data;
  228. j->whatto = whatto;
  229. j->next = a_tcp->listeners;
  230. a_tcp->listeners = j;
  231. }
  232.  }
  233. if (!a_tcp->listeners)
  234.  {/*不存在监听着*/
  235. free_tcp(a_tcp);
  236. return;
  237. }
  238. a_tcp->nids_state = NIDS_DATA;
  239. }
  240. }
  241. //
  242.  return;
  243.  }
  244. }
  245. /*
  246. ************************************************************
  247.  
  248.                 挥手过程
  249.  
  250. *************************************************************
  251.  
  252. */
  253.     
  254. /*数据结束的包的判断*/
  255.  if ((this_tcphdr->th_flags & TH_ACK)) {
  256. /* 从数据传输过程不断更新服务器客户端的ack_seq
  257.     一直到接收到fin 包,数据传输结束
  258.  
  259. */
  260. //先调用handle_ack更新ack序号
  261.  handle_ack(snd, ntohl(this_tcphdr->th_ack));
  262. //更新状态,回调告知连接关闭,然后释放连接
  263.  if (rcv->state == FIN_SENT)
  264. rcv->state = FIN_CONFIRMED;
  265. if (rcv->state == FIN_CONFIRMED && snd->state == FIN_CONFIRMED
  266.  {
  267. struct lurker_node *i;
  268. a_tcp->nids_state = NIDS_CLOSE;
  269. for (i = a_tcp->listeners; i; i = i->next)
  270. (i->item) (a_tcp, &i->data);
  271. free_tcp(a_tcp);
  272.  return;
  273.  }
  274. }
  275. /*
  276.  
  277. *************************************************************
  278.                         数据处理过程
  279. *************************************************************
  280.  
  281.  */
  282.   
  283.  if (datalen + (this_tcphdr->th_flags & TH_FIN) > 0) /*
  284.            
  285.     a_tcp -----a_tcp 客户端连接包
  286.     this_tcphdr tcp 包头
  287.     snd-----发送包
  288.     rcv -----接收包
  289.  
  290.     (char *) (this_tcphdr) + 4 * this_tcphdr->th_off -----数据包内容
  291.     datalen---------数据包长度
  292.        
  293.  
  294. */
  295. //就将数据更新到接收方缓冲区
  296. tcp_queue(a_tcp, this_tcphdr, snd, rcv, (char *) (this_tcphdr) + 4 * this_tcphdr->th_off, datalen, skblen);
  297. //更新窗口大小
  298.  snd->window = ntohs(this_tcphdr->th_win);
  299. //如果缓存溢出(说明出了问题),果断释放连接
  300.  if (rcv->rmem_alloc > 65535) prune_queue(rcv, this_tcphdr); if (!a_tcp->listeners) free_tcp(a_tcp);}

相关结构体说明

点击(此处)折叠或打开

  1. struct timestamp
  2.   {
  3.     u_int8_t len;
  4.     u_int8_t ptr;
  5. #if __BYTE_ORDER == __LITTLE_ENDIAN
  6.     unsigned int flags:4;
  7.     unsigned int overflow:4;
  8. #elif __BYTE_ORDER == __BIG_ENDIAN
  9.     unsigned int overflow:4;
  10.     unsigned int flags:4;
  11. #else
  12. # error "Please fix "
  13. #endif
  14.     u_int32_t data[9];
  15.   };
  16.   
  17. struct iphdr
  18.   {
  19. #if __BYTE_ORDER == __LITTLE_ENDIAN
  20.     unsigned int ihl:4;
  21.     unsigned int version:4;
  22. #elif __BYTE_ORDER == __BIG_ENDIAN
  23.     unsigned int version:4;
  24.     unsigned int ihl:4;
  25. #else
  26. # error "Please fix "
  27. #endif
  28.     u_int8_t tos;
  29.     u_int16_t tot_len;
  30.     u_int16_t id;
  31.     u_int16_t frag_off;
  32.     u_int8_t ttl;
  33.     u_int8_t protocol;
  34.     u_int16_t check;
  35.     u_int32_t saddr;
  36.     u_int32_t daddr;
  37.     /*The options start here. */
  38.   };
  39. <pre name="code" class="cpp"><pre></pre>
  40. <p></p>
  41. <pre></pre>
  42. tcp结构
  43. <p></p>
  44. <p></p>
  45. <pre name="code" class="cpp">struct tcphdr {
  46.     __be16 source;
  47.     __be16 dest;
  48.     __be32 seq;
  49.     __be32 ack_seq;
  50. #if defined(__LITTLE_ENDIAN_BITFIELD)
  51.     __u16 res1:4,
  52.             doff:4,
  53.             fin:1,
  54.             syn:1,
  55.             rst:1,
  56.             psh:1,
  57.             ack:1,
  58.             urg:1,
  59.             ece:1,
  60.             cwr:1;
  61. #elif defined(__BIG_ENDIAN_BITFIELD)
  62.     __u16 doff:4,
  63.             res1:4,
  64.             cwr:1,
  65.             ece:1,
  66.             urg:1,
  67.             ack:1,
  68.             psh:1,
  69.             rst:1,
  70.             syn:1,
  71.             fin:1;
  72. #else
  73. #error "Adjust your defines"
  74. #endif
  75.     __be16 window;
  76.     __be16 check;
  77.     __be16 urg_ptr;
  78. };

查找是否存在tcp流

点击(此处)折叠或打开

  1. struct tcp_stream *
  2. find_stream(struct tcphdr * this_tcphdr, struct ip * this_iphdr,
  3.         int *from_client)
  4. {
  5.   struct tuple4 this_addr, reversed;
  6.   int hash_index;
  7.   struct tcp_stream *a_tcp;
  8.   
  9.   this_addr.source = ntohs(this_tcphdr->th_sport);
  10.   this_addr.dest = ntohs(this_tcphdr->th_dport);
  11.   this_addr.saddr = this_iphdr->ip_src.s_addr;
  12.   this_addr.daddr = this_iphdr->ip_dst.s_addr;
  13.   hash_index = mk_hash_index(this_addr);//找到传入数据的哈希地址
  14.   for (a_tcp = tcp_stream_table[hash_index];
  15.        a_tcp && !b_comp(a_tcp->addr, this_addr);
  16.        a_tcp = a_tcp->next_node);//如果此地址开始即为空,则表明没有与此包对应的TCP流,如果该地址不为空,则看地址值是否一样,如果
  17.          //找到,设定from_client = 1,否则,一直找到最后。看是否为同一个TCP流主要看其地址是否一样
  18.   if (a_tcp) {
  19.     *from_client = 1;
  20.     return a_tcp;
  21.   }
  22.   reversed.source = ntohs(this_tcphdr->th_dport);
  23.   reversed.dest = ntohs(this_tcphdr->th_sport);
  24.   reversed.saddr = this_iphdr->ip_dst.s_addr;
  25.   reversed.daddr = this_iphdr->ip_src.s_addr;
  26.   hash_index = mk_hash_index(reversed);
  27.   for (a_tcp = tcp_stream_table[hash_index];
  28.        a_tcp && !b_comp(a_tcp->addr, reversed);
  29.        a_tcp = a_tcp->next_node);
  30.   if (a_tcp) {
  31.     *from_client = 0;
  32.     return a_tcp;
  33.   }
  34.   else
  35.     return 0;
  36. }

点击(此处)折叠或打开

  1. struct tcp_stream *
  2. find_stream(struct tcphdr * this_tcphdr, struct ip * this_iphdr,
  3.         int *from_client)
  4. {
  5.   struct tuple4 this_addr, reversed;
  6.   int hash_index;
  7.   struct tcp_stream *a_tcp;
  8.   
  9.   this_addr.source = ntohs(this_tcphdr->th_sport);
  10.   this_addr.dest = ntohs(this_tcphdr->th_dport);
  11.   this_addr.saddr = this_iphdr->ip_src.s_addr;
  12.   this_addr.daddr = this_iphdr->ip_dst.s_addr;
  13.   hash_index = mk_hash_index(this_addr);//找到传入数据的哈希地址
  14.   for (a_tcp = tcp_stream_table[hash_index];
  15.        a_tcp && !b_comp(a_tcp->addr, this_addr);
  16.        a_tcp = a_tcp->next_node);//如果此地址开始即为空,则表明没有与此包对应的TCP流,如果该地址不为空,则看地址值是否一样,如果
  17.          //找到,设定from_client = 1,否则,一直找到最后。看是否为同一个TCP流主要看其地址是否一样
  18.   if (a_tcp) {
  19.     *from_client = 1;
  20.     return a_tcp;
  21.   }
  22.   reversed.source = ntohs(this_tcphdr->th_dport);
  23.   reversed.dest = ntohs(this_tcphdr->th_sport);
  24.   reversed.saddr = this_iphdr->ip_dst.s_addr;
  25.   reversed.daddr = this_iphdr->ip_src.s_addr;
  26.   hash_index = mk_hash_index(reversed);
  27.   for (a_tcp = tcp_stream_table[hash_index];
  28.        a_tcp && !b_comp(a_tcp->addr, reversed);
  29.        a_tcp = a_tcp->next_node);
  30.   if (a_tcp) {
  31.     *from_client = 0;
  32.     return a_tcp;
  33.   }
  34.   else
  35.     return 0;
  36. }

当没有找到一个与之对应已存在的TCP流是,添加一个新的TCP流。调用函数:add_new_tcp(this_tcphdr, this_iphdr);

点击(此处)折叠或打开

  1. static void
  2. add_new_tcp(struct tcphdr * this_tcphdr, struct ip * this_iphdr)
  3. {
  4.   struct tcp_stream *tolink;
  5.   struct tcp_stream *a_tcp;
  6.   int hash_index;
  7.   struct tuple4 addr;
  8.     
  9.   addr.source = ntohs(this_tcphdr->th_sport);
  10.   addr.dest = ntohs(this_tcphdr->th_dport);
  11.   addr.saddr = this_iphdr->ip_src.s_addr;
  12.   addr.daddr = this_iphdr->ip_dst.s_addr;
  13.   hash_index = mk_hash_index(addr);//计算新的TCP流的哈希地址
  14.     
  15.   if (tcp_num > max_stream) {//tcp流的大小超过了阈值,需要先释放空间
  16.     struct lurker_node *i;
  17.       
  18.     tcp_oldest->nids_state = NIDS_TIMED_OUT;
  19.     for (i = tcp_oldest->listeners; i; i = i->next)
  20.       (i->item) (tcp_oldest, &i->data);
  21.     free_tcp(tcp_oldest);
  22.     nids_params.syslog(NIDS_WARN_TCP, NIDS_WARN_TCP_TOOMUCH, ugly_iphdr, this_tcphdr);
  23.   }
  24.   a_tcp = free_streams;加入流的地址
  25.   if (!a_tcp) {
  26.     fprintf(stderr, "gdb me ...\n");
  27.     pause();
  28.   }
  29.   free_streams = a_tcp->next_free;
  30.     
  31.   tcp_num++;//流的总数加1
  32.   tolink = tcp_stream_table[hash_index];
  33.   memset(a_tcp, 0, sizeof(struct tcp_stream));
  34.   a_tcp->hash_index = hash_index;
  35.   a_tcp->addr = addr;
  36.   a_tcp->client.state = TCP_SYN_SENT;
  37.   a_tcp->client.seq = ntohl(this_tcphdr->th_seq) + 1;
  38.   a_tcp->client.first_data_seq = a_tcp->client.seq;
  39.   a_tcp->client.window = ntohs(this_tcphdr->th_win);
  40.   a_tcp->client.ts_on = get_ts(this_tcphdr, &a_tcp->client.curr_ts);
  41.   a_tcp->client.wscale_on = get_wscale(this_tcphdr, &a_tcp->client.wscale);
  42.   a_tcp->server.state = TCP_CLOSE;
  43.   a_tcp->next_node = tolink;
  44.   a_tcp->prev_node = 0;
  45.   if (tolink)
  46.     tolink->prev_node = a_tcp;
  47.   tcp_stream_table[hash_index] = a_tcp;
  48.   a_tcp->next_time = tcp_latest;
  49.   a_tcp->prev_time = 0;
  50.   if (!tcp_oldest)
  51.     tcp_oldest = a_tcp;
  52.   if (tcp_latest)
  53.     tcp_latest->prev_time = a_tcp;
  54.   tcp_latest = a_tcp;
  55. }

下面来看TCP重组过程当中的三次握手:

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手后,开始传送数据。

/*******************************************************************************************************************

                                                     第一次握手

*******************************************************************************************************************/

点击(此处)折叠或打开

  1. if (!(a_tcp = find_stream(this_tcphdr, this_iphdr, &from_client))) {
  2.     
  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.     /*并且没有收到th_rest 包*/
  10.       add_new_tcp(this_tcphdr, this_iphdr);/*节点加入链表中*/
  11.     
  12.    /*第一次握手完毕返回*/
  13.     return;
  14.   }
  15.     
  16.       
  17.   if (from_client) { /*从client --> server的包*/
  18.     snd = &a_tcp->client;
  19.     rcv = &a_tcp->server;
  20.   }
  21.   else {/* server --> client的包 */
  22.     rcv = &a_tcp->client;
  23.     snd = &a_tcp->server;
  24.   }

/*******************************************************************************************************************

                                                     第二次握手

*******************************************************************************************************************/

点击(此处)折叠或打开

  1. /*tcp 三次握手, SYN ==1,ACK==1,tcp第二次握手(server -> client的同步响应)*/
  2.   if ((this_tcphdr->th_flags & TH_SYN)) {
  3.     if (from_client || a_tcp->client.state != TCP_SYN_SENT ||
  4.       a_tcp->server.state != TCP_CLOSE || !(this_tcphdr->th_flags & TH_ACK))
  5.       return;
  6.     
  7.     
  8. /*第二次回应包的ACK 值为第一个包的序列号+1,在初始化的时候已经加一*/
  9.     if (a_tcp->client.seq != ntohl(this_tcphdr->th_ack))
  10.       return;
  11.          
  12.          
  13.     /*第二个包服务端赋值*/
  14.     /*a_tcp 中服务端赋值,*/
  15.     
  16.     a_tcp->server.state = TCP_SYN_RECV;
  17.     a_tcp->server.seq = ntohl(this_tcphdr->th_seq) + 1;
  18.     a_tcp->server.first_data_seq = a_tcp->server.seq;
  19.     a_tcp->server.ack_seq = ntohl(this_tcphdr->th_ack);
  20.     a_tcp->server.window = ntohs(this_tcphdr->th_win);
  21.     
  22.     
  23.   /*对于tcp 选项的赋值*/
  24.   //初始化客户端和服务器的时间截
  25.   
  26.     if (a_tcp->client.ts_on) {
  27.         a_tcp->server.ts_on = get_ts(this_tcphdr, &a_tcp->server.curr_ts);
  28.     if (!a_tcp->server.ts_on)
  29.         a_tcp->client.ts_on = 0;
  30.     } else a_tcp->server.ts_on = 0;
  31.     
  32.     
  33. //初始化窗口大小
  34.   
  35.     if (a_tcp->client.wscale_on) {
  36.         a_tcp->server.wscale_on = get_wscale(this_tcphdr, &a_tcp->server.wscale);
  37.     if (!a_tcp->server.wscale_on) {
  38.         a_tcp->client.wscale_on = 0;
  39.         a_tcp->client.wscale = 1;
  40.         a_tcp->server.wscale = 1;
  41.     }
  42.     } else {
  43.         a_tcp->server.wscale_on = 0;
  44.         a_tcp->server.wscale = 1;
  45.     }
  46.  /*第二次握手完毕,返回*/
  47.          
  48.     return;
  49.   }

完成第二次握手后,需要对一些数据进行处理,代码如下:

点击(此处)折叠或打开

  1. /*
  2.                 (如果有数据存在或者修列号不等于确认号的)并且

  3.         序列号在窗口之外
  4.         已经确认过的序号

  5.    */
  6.     
  7.   if (
  8.     ! (!datalen &&ntohl(this_tcphdr->th_seq)== rcv->ack_seq)
  9.     &&
  10.   
  11.     /*th_seq - (ack_seq+ wscale) > 0 或者th_seq+datalen - ack_sql < 0*/
  12.     ( !before(ntohl(this_tcphdr->th_seq), rcv->ack_seq+ rcv->window*rcv->wscale)||
  13.           before(ntohl(this_tcphdr->th_seq)+ datalen, rcv->ack_seq)
  14.         )
  15.      )
  16.      return;
  17.   
  18.      
  19.   
  20.   /*发送th_rst 重新开启一个连接*/
  21.   if ((this_tcphdr->th_flags& TH_RST)){
  22.     /*是tcp 数据*/
  23.     if (a_tcp->nids_state== NIDS_DATA){
  24.       struct lurker_node *i;
  25.       a_tcp->nids_state= NIDS_RESET;
  26.       for (i= a_tcp->listeners; i; i= i->next)
  27.     (i->item)(a_tcp, &i->data);
  28.     }
  29.     nids_free_tcp_stream(a_tcp);
  30.     return;
  31.   }


然后开始第三次握手

/*******************************************************************************

                                     第三次握手

******************************************************************************/

点击(此处)折叠或打开

  1. /*从client --> server的包

  2.    是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
  3.    连接状态

  4.   */
  5.      
  6.   if ((this_tcphdr->th_flags& TH_ACK)){
  7.     if (from_client&& a_tcp->client.state== TCP_SYN_SENT&&
  8.     a_tcp->server.state== TCP_SYN_RECV){
  9.       if (ntohl(this_tcphdr->th_ack)== a_tcp->server.seq){
  10.     a_tcp->client.state= TCP_ESTABLISHED;
  11.     a_tcp->client.ack_seq= ntohl(this_tcphdr->th_ack);
  12.     {
  13.       struct proc_node *i;
  14.       struct lurker_node *j;
  15.       void *data;
  16.          
  17.       a_tcp->server.state= TCP_ESTABLISHED;
  18.       a_tcp->nids_state= NIDS_JUST_EST;
  19.       /*开始全双工传输,client server 连接已经建立起来了*/
  20.   
  21.       /*三次握手tcp ip 连接建立*/
  22.       for (i= tcp_procs; i; i= i->next){
  23.         char whatto = 0;
  24.            
  25.         char cc = a_tcp->client.collect;
  26.         char sc = a_tcp->server.collect;
  27.         char ccu = a_tcp->client.collect_urg;
  28.         char scu = a_tcp->server.collect_urg;
  29.   
  30.         /*进入回调函数处理*/
  31.   
  32.         /*

  33.             如果在相应端口出现

  34.         client.collect ++ ;

  35.         测审计次数据
  36.         对应用来说tcp 连接已经建立

  37.        */
  38.           
  39.           
  40.         (i->item)(a_tcp, &data);
  41.   
  42.        /**/
  43.         if (cc< a_tcp->client.collect)
  44.           whatto |= COLLECT_cc;
  45.         if (ccu< a_tcp->client.collect_urg)
  46.           whatto |= COLLECT_ccu;
  47.         if (sc< a_tcp->server.collect)
  48.           whatto |= COLLECT_sc;
  49.         if (scu< a_tcp->server.collect_urg)
  50.           whatto |= COLLECT_scu;
  51.         if (nids_params.one_loop_less){
  52.                 if (a_tcp->client.collect>=2){
  53.                     a_tcp->client.collect=cc;
  54.                     whatto&=~COLLECT_cc;
  55.                 }
  56.                 if (a_tcp->server.collect>=2 ) {
  57.                     a_tcp->server.collect=sc;
  58.                     whatto&=~COLLECT_sc;
  59.                 }
  60.         }
  61.               
  62.        /*加入监听队列,开始数据接收*/
  63.         if (whatto){
  64.           j = mknew(struct lurker_node);
  65.           j->item= i->item;/*放入监听队列*/
  66.           j->data= data;
  67.           j->whatto= whatto;
  68.              
  69.           j->next= a_tcp->listeners;
  70.           a_tcp->listeners= j;
  71.         }
  72.            
  73.       }
  74.          
  75.          
  76.       /*不存在监听着*/{
  77.         nids_free_tcp_stream(a_tcp);
  78.         return;
  79.       }
  80.       if (!a_tcp->listeners)
  81.          
  82.       a_tcp->nids_state= NIDS_DATA;
  83.     }
  84.       }
  85.       // return;

  86.     }
  87.   }


nids头文件定义

点击(此处)折叠或打开

  1. 从client --> server的包

  2.    是从三次握手的第三个包分析开始的,进行一部分数据分析,和初始化
  3.    连接状态

  4.   */
  5.      
  6.   if ((this_tcphdr->th_flags& TH_ACK)){
  7.     if (from_client&& a_tcp->client.state== TCP_SYN_SENT&&
  8.     a_tcp->server.state== TCP_SYN_RECV){
  9.       if (ntohl(this_tcphdr->th_ack)== a_tcp->server.seq){
  10.     a_tcp->client.state= TCP_ESTABLISHED;
  11.     a_tcp->client.ack_seq= ntohl(this_tcphdr->th_ack);
  12.     {
  13.       struct proc_node *i;
  14.       struct lurker_node *j;
  15.       void *data;
  16.          
  17.       a_tcp->server.state= TCP_ESTABLISHED;
  18.       a_tcp->nids_state= NIDS_JUST_EST;
  19.       /*开始全双工传输,client server 连接已经建立起来了*/
  20.   
  21.       /*三次握手tcp ip 连接建立*/
  22.       for (i= tcp_procs; i; i= i->next){
  23.         char whatto = 0;
  24.            
  25.         char cc = a_tcp->client.collect;
  26.         char sc = a_tcp->server.collect;
  27.         char ccu = a_tcp->client.collect_urg;
  28.         char scu = a_tcp->server.collect_urg;
  29.   
  30.         /*进入回调函数处理*/
  31.   
  32.         /*

  33.             如果在相应端口出现

  34.         client.collect ++ ;

  35.         测审计次数据
  36.         对应用来说tcp 连接已经建立

  37.        */
  38.           
  39.           
  40.         (i->item)(a_tcp, &data);
  41.   
  42.        /**/
  43.         if (cc< a_tcp->client.collect)
  44.           whatto |= COLLECT_cc;
  45.         if (ccu< a_tcp->client.collect_urg)
  46.           whatto |= COLLECT_ccu;
  47.         if (sc< a_tcp->server.collect)
  48.           whatto |= COLLECT_sc;
  49.         if (scu< a_tcp->server.collect_urg)
  50.           whatto |= COLLECT_scu;
  51.         if (nids_params.one_loop_less){
  52.                 if (a_tcp->client.collect>=2){
  53.                     a_tcp->client.collect=cc;
  54.                     whatto&=~COLLECT_cc;
  55.                 }
  56.                 if (a_tcp->server.collect>=2 ) {
  57.                     a_tcp->server.collect=sc;
  58.                     whatto&=~COLLECT_sc;
  59.                 }
  60.         }
  61.               
  62.        /*加入监听队列,开始数据接收*/
  63.         if (whatto){
  64.           j = mknew(struct lurker_node);
  65.           j->item= i->item;/*放入监听队列*/
  66.           j->data= data;
  67.           j->whatto= whatto;
  68.              
  69.           j->next= a_tcp->listeners;
  70.           a_tcp->listeners= j;
  71.         }
  72.            
  73.       }
  74.          
  75.          
  76.       /*不存在监听着*/{
  77.         nids_free_tcp_stream(a_tcp);
  78.         return;
  79.       }
  80.       if (!a_tcp->listeners)
  81.          
  82.       a_tcp->nids_state= NIDS_DATA;
  83.     }
  84.       }
  85.       // return;

  86.     }
  87.   }
















阅读(3694) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~