Libnids基础和TCP数据流

目录

 

本文内容

器材(设备、元器件)

正文

1.Libnids是什么?可以干什么?

2.ids做软件开发流程

3. ids主要函数

4.ids实现tcp流程序分析框架

5.使用NIDS库编写TCP流分析程序,解释和输出三个结构体tuple4,half_stream,nids_prm的值

 


  • 本文内容

1.Libnids是什么?可以干什么?

2.ids做软件开发流程

3. ids主要函数

4.ids实现tcp流程序分析框架

5.使用NIDS库编写TCP流分析程序,解释和输出三个结构体tuple4,half_stream,nids_prm的值

 

  • 器材(设备、元器件)

    Ubuntu虚拟机内QT编程

 

  • 正文

  • 1.Libnids是什么?可以干什么?

Libnids是一个用于网络入侵检测开发的专业编程接口。主要功能包括捕获网络数据包、IP碎片重组、TCP数据流重组【对分析单个TCP数据包和整个TCP连接过程,以及应用层FTP、HTTP、POP3协议有帮助】以及端口扫描攻击检测和异常数据包检测、网络嗅探等。

 

2.ids做软件开发流程

1)、用函数nids_init()进行初始化

2)、注册相应的回调函数,不同的回调函数实现不同的功能

3)、利用函数nids_run()进入循环捕获数据包的状态

 

3. ids主要函数

基本函数:

(1)int  nids_init(void);//对libnids进行初始化

(2)void nids_run(void);//运行Libnids,进入循环捕获数据包状态.

(3)int nids_getfd(void);//获得文件描述号

(4)int nids_dispatch(int cnt)//功能是调用Libpcap中的捕获数据包函数pcap_dispatch().

(5)int nids_next(void)//调用Libpcap中的捕获数据包函数pcap_next()

(6)void nids_register_chksum_ctl(struct nids_chksum_ctl *ptr,int nr)//决定是否计算校验和,它是根据数据结构nids_chksum_ctl中的action进行决定的

 

IP碎片函数:

(1)void nids_register_ip_frag(void(*))//此函数的功能是注册一个能够检测所有IP数据包的回调函数,包括IP碎片

eg:nids_register_ip_frag(ip_frag_function);这样就定义了一个回调函数ip_frag_function的定义类型如下:

void ip_frag_function(struct ip *a_packet,int len)

(2)void nids_register_ip(void(*))//此函数定义一个回调函数,此回调函数可以接受正常的IP数据包,eg:nids_register_ip(ip_function);此回调函数的定义类型如下:

void ip_function(struct ip * a_packet)

 

TCP数据流重组函数:

(1)void nids_register_tcp(void(*))

回调函数的功能是注册一个TCP连接的回调函数,回调函数的类型定义如下:

void tcp_callback(struct tcp_stream *ns,void **param);

其中参数ns表示一个tcp连接的所有信息,它的类型是tcp_stream数据结构;参数param表示要传递的连接参数信息,可以指向一个TCP连接的私有数据

(2)void nids_killtcp(struct tcp_stream * a_tcp)//此函数功能是终止TCP连接

(3)void nids_discard(struct tcp_stream *a_tcp,int num)//丢弃num字节TCP数据,用于存储更多的数据

 

4.ids实现tcp流程序分析框架

C语言实现,来自《网络数据获取与协议分析》

#include "nids.h"
#include "pcap.h"
#include "libnet.h"
/* Libnids的头文件,必须包含 */
char ascii_string[10000];
char *char_to_ascii(char ch)
/* 此函数的功能主要用于把协议数据进行显示 */
{
    char *string;
    ascii_string[0] = 0;
    string = ascii_string;
    if (isgraph(ch))
     /* 可打印字符 */
    {
        *string++ = ch;
    }
    else if (ch == ' ')
     /* 空格 */
    {
        *string++ = ch;
    }
    else if (ch == '\n' || ch == '\r')
     /* 回车和换行 */
    {
        *string++ = ch;
    }
    else
     /* 其它字符以点"."表示 */
    {
        *string++ = '.';
    }
    *string = 0;
    return ascii_string;
}
/*
====================================================================================
下面的函数是回调函数,用于分析TCP连接,分析TCP连接状态,对TCP协议传输的数据进行分析
====================================================================================
 */
void tcp_protocol_callback(struct tcp_stream *tcp_connection, void **arg)
{
    int i;
    char address_string[1024];
    char content[65535];
    char content_urgent[65535];
    struct tuple4 ip_and_port = tcp_connection->addr;
    /* 获取TCP连接的地址和端口对 */
    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
    /* 获取源地址 */
    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);
    /* 获取源端口 */
    strcat(address_string, " <---> ");
    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
    /* 获取目的地址 */
    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);
    /* 获取目的端口 */
    strcat(address_string, "\n");
    switch (tcp_connection->nids_state) /* 判断LIBNIDS的状态 */
    {
        case NIDS_JUST_EST:
            /* 表示TCP客户端和TCP服务器端建立连接状态 
在此状态下就可以决定是否对此TCP连接进行数据分析,可以决定是否捕获TCP客户端接收的数据、TCP服务器端接收的数据、TCP客户端接收的紧急数据或者TCP服务器端接收的紧急数据*/
            tcp_connection->client.collect++;
            /* 客户端接收数据 */
            tcp_connection->server.collect++;
            /* 服务器接收数据 */
            tcp_connection->server.collect_urg++;
            /* 服务器接收紧急数据 */
            tcp_connection->client.collect_urg++;
            /* 客户端接收紧急数据 */
            printf("%sTCP连接建立\n", address_string);
            return ;
        case NIDS_CLOSE:
            /* 表示TCP连接正常关闭 */
            printf("--------------------------------\n");
            printf("%sTCP连接正常关闭\n", address_string);
            return ;
        case NIDS_RESET:
            /* 表示TCP连接被重置关闭 */
            printf("--------------------------------\n");
            printf("%sTCP连接被RST关闭\n", address_string);
            return ;
        case NIDS_DATA:
            /* 表示有新的数据到达在这个状态可以判断是否有新的数据到达,如果有就可以把数据存储起来,可以在这个状态之中来分析TCP传输的数据,此数据就存储在half_stream数据结构的缓存之中。 */
            {
                struct half_stream *hlf;
                /* 表示TCP连接的一端的信息,可以是客户端,也可以是服务器端 */
                if (tcp_connection->server.count_new_urg)
                {
                    /* 表示TCP服务器端接收到新的紧急数据 */
                    printf("--------------------------------\n");
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);
                    strcat(address_string, " urgent---> ");
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);
                    strcat(address_string, "\n");
                    address_string[strlen(address_string) + 1] = 0;
                    address_string[strlen(address_string)] = tcp_connection->server.urgdata;
                    printf("%s", address_string);
                    return ;
                }
                if (tcp_connection->client.count_new_urg)
                {
                    /* 表示TCP客户端接收到新的紧急数据 */
                    printf("--------------------------------\n");
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);
                    strcat(address_string, " <--- urgent ");
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
                    sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);
                    strcat(address_string, "\n");
                    address_string[strlen(address_string) + 1] = 0;
                    address_string[strlen(address_string)] = tcp_connection->client.urgdata;
                    printf("%s", address_string);
                    return ;
                }
                if (tcp_connection->client.count_new)
                {
                    /* 表示客户端接收到新的数据 */
                    hlf = &tcp_connection->client;
                    /* 此时hlf表示的是客户端的TCP连接信息 */
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);
                    strcat(address_string, " <--- ");
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);
                    strcat(address_string, "\n");
                    printf("--------------------------------\n");
                    printf("%s", address_string);
                    memcpy(content, hlf->data, hlf->count_new);
                    content[hlf->count_new] = '\0';
                    printf("客户端接收数据\n");
                    for (i = 0; i < hlf->count_new; i++)
                    {
                        printf("%s", char_to_ascii(content[i]));
                        //输出客户端接收的新的数据,以可打印字符进行显示
                    }
                    printf("\n");
                }
                else
                {
                    /* 表示服务器端接收到新的数据 */
                    hlf = &tcp_connection->server;
                    /* 此时hlf表示服务器端的TCP连接信息 */
                    strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);
                    strcat(address_string, " ---> ");
                    strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));
                    sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);
                    strcat(address_string, "\n");
                    printf("--------------------------------\n");
                    printf("%s", address_string);
                    memcpy(content, hlf->data, hlf->count_new);
                    content[hlf->count_new] = '\0';
                    printf("服务器端接收数据:\n");
                    for (i = 0; i < hlf->count_new; i++)
                    {
                        printf("%s", char_to_ascii(content[i]));
                        // 输出服务器接收到的新的数据
                    }
                    printf("\n");
                }
            }
        default:
            break;
    }
    return ;
}
void main()
{
    struct nids_chksum_ctl temp;
    temp.netaddr = 0;
    temp.mask = 0;
    temp.action = 1;
nids_register_chksum_ctl(&temp,1);  
/*这段是相关与计算校验和的,比较新的网卡驱动会自动计算校验和,我们要做的就是把它关掉*/
    if (!nids_init())
     /* Libnids初始化 */
    {
        printf("出现错误:%s\n", nids_errbuf);
        exit(1);
    }
    nids_register_tcp(tcp_protocol_callback);
    /* 注册回调函数 */
    nids_run();
    /* Libnids进入循环捕获数据包状态 */

 

5.使用NIDS库编写TCP流分析程序,解释和输出三个结构体tuple4,half_stream,nids_prm的值

 

tuple4

Struct tuple4

{

  u_short source;

/*成员source表示源IP地址的端口号;*/

  u_short dest;

/*成员dest表示目的IP地址的目的端口号。*/

  u_int saddr;

/*成员saddr表示一个TCP连接的一端IP地址,称为源IP地址;*/

  u_int daddr;

/*成员daddr表示一个TCP连接的另一端IP地址,称为目的IP地址,注意此时的源和目的只是相对的;*/

};

half_stream:

struct half_stream      

  /* 描述在 TCP 连接中一端的所有信息 , 可以是客户端 , 也可以是服务端 */

{

  char state;                 

/* 表示套接字的状态 , 也就是 TCP 的状态 */

  char collect;              

/* 可以表示有数据到达 , 此数据存放在 data 成员中 , 也可以表示不存储此数据到 data 中 , 此数据忽略 . 如果大于 0 就存储 , 否则就忽略 */

  char collect_urg;       

/* 可以表示有紧急数据到达 , 此数据就存放在 urgdata 中 , 也可以表示不存储此数据到 urgdata 中 , 此速数据忽略 . 如果大于 0 就存储 , 否则就忽略 */

   char *data;               

 /* 用户存储正常接受到的数据 */

  int offset;                  

/* 表示存储在 data 中数据的第一个字节的偏移量 */

  int count;                  

/* 表示从 TCP 连接开始已经存储到 data 中的数据的字节数 */

  int count_new;         

/* 有多少新的数据存储到 data 中 , 如果为 0, 则表示没有新的数据到达 */

  int bufsize;

  int rmem_alloc;

   int urg_count;  

/* 用来存储紧急数据 */

 u_int acked;    

  u_int seq;

  u_int ack_seq;

  u_int first_data_seq;

  u_char urgdata;

  u_char count_new_urg;     

/* 表示有新的紧急数据到达 , 如果为 0 表示没有新的紧急数据 */

  u_char urg_seen;      

  u_int urg_ptr;

  u_short window;     

  u_char ts_on;

  u_char wscale_on;

  u_int curr_ts;

  u_int wscale;

  struct skbuff *list;

  struct skbuff *listtail;

};

 

Libnids 全局参数: 利用它可以对Libnids的一些环境参数进行设置,设置之后对整个Libnids都有效。

struct nids_prm

{

  int n_tcp_streams;

/*表示哈西表大小,此哈西表用来存放tcp_stream数据结构,默认值为1040。在同一时刻Libnids捕获的TCP数据包的最大个数必须是此参数值的3/4。

*/

  int n_hosts;

/*表示哈西表的大小,此哈西表是用来存储IP碎片信息的,默认值为256。*/

  char *device;

/*表示网络接口,Libnids将在此网络接口上捕获数据,默认值为NULL。这样Libnids将使用pcap_lookupdev来查找可用的网络接口。如果其值为all,表示捕获所有网络接口的数据。*/

  char *filename;

/*表示用来存储网络数据的捕获文件。此文件的类型必须与Libpcap类型一致。如果设置了文件,与此同时就应该设置成员device为NULL,默认值为NULL*/

  int sk_buff_size;

/*表示的是数据结构sk_buff的人小。数据结构sk_buff是Linux内核中一个重要的数据结构,是用来进行数据包排队操作的,默认值为168。*/

  int dev_addon;

/*表示在数据结构sk_buff中用于网络接口上信息的字节数。如果是-1(默认值),那么Libnids会根据不同的网络接口进行修正。*/

  void (*syslog) ();

/*成员syslog是一个函数指针,默认值为nids_syslog()函数。在syslog函数中可以检测入侵攻击,如网络扫描攻击,也可以检测一些异常情况,如无效TCP标记.*/

  int syslog_level;

/*表示日志等级,默认值为LOG_ALERT*/

  int scan_num_hosts;

/*表示一个哈西表的大小,(此哈西表用来存储端口扫描信息)表示Libnids将要检测的同时扫描的端口数据。如果其值为0,Libnids将不提供端口扫描功能。默认值为256。*/

  int scan_delay;

/*表示在扫描检测中,两端口扫描的间隔时间,以毫秒来计算,缺省值为3000*/

  int scan_num_ports;

/*表示相同源地址必须扫描的TCP端口数目,默认值为10*/

  void (*no_mem) (char *);

/*一个函数指针,当Libnids发生内存溢出时被调用*/

  int (*ip_filter) ();

/*一个函数指针,此函数可以用来分析IP数据包,当有IP数据包到达时,此函数就被调用。如果此函数返回非零值,此数据包就被处理;如果返回零,此IP数据包就被丢弃。默认值为nids_ip_filter函数,总是返回1*/

  char *pcap_filter;

/*表示过滤规则,即Libpcap的过滤规则,默认值为NULL,表示捕获所有数据包。可以在此设置过滤规则,只捕获感兴趣的开发包*/

  int promisc;

/*表示网卡模式,如果是非零,就把此网卡设为混杂模式:否则,设为非混杂模式。默认值为1*/

  int one_loop_less;

/*初始值为0*/

  int pcap_timeout;

/*表示捕获数据返回的时间,以毫秒计算。实际上它表示的就是Libpcap函数中的pcap_open_live函数的timeout参数,默认值为1024*/

  int multiproc;

  int queue_limit;

  int tcp_workarounds;

  pcap_t *pcap_desc;

};

猜你喜欢

转载自blog.csdn.net/Zhou_ZiZi/article/details/84985017