libnids 安装编译与测试

一、linux下编译安装libnids库

1、安装libpcap(略)

2、安装libnet:

源文件下载地址:http://sourceforge.net/projects/libnet-dev/files/
解压:tar -zxvf libnet-1.2-rc3.tar.gz

cd libnet-1.2-rc3
./configure
make
make install

安装完以后,配置一下动态库路径,否则libnids编译时找不到

方法一:(推荐)
在/etc/ld.so.conf.d 目录下,新建 libnet.conf
内容为 /usr/local/lib
执行 ldconfig

方法二
cat /etc/ld.so.conf
echo "/usr/local/lib" >> /etc/ld.so.conf
ldconfig

如果有提示 /usr/local/lib/libglibxxx.6.20.xx.gdb.py 不是有效ELF文件,可以把该文件删除
qt的话,可能要重新选择调试器,否则可能无法调试

3、安装libnids:

源文件下载地址:http://sourceforge.net/projects/libnids/files/
解压:tar -zxvf libnids-1.24.tar.gz

cd libnids-1.24
./configure
make
make install

我用的是centos6.5,会configure会提示出错
configure: error: Cannot find eventlog version >= 0.2: is pkg-config in path
解决方案: 安装glib2-deve
yum -y installglib2-devel

4、用gcc编译源文件时后面加上:-lpcap -lnet -lnids -lgthread-2.0,因为libnids 1.22以后使用了,glib2库中的gthread-2.0来实现多线程提高效率,因此在编译除了-lnids -lpcap -lnet 以外还要加上 -lgthread-2.0

5、编译用 g++编译时出错,gcc编译提示警告,g++版本4.94

g++ hello.cpp -lpcap -lnet -lnids -lgthread-2.0

hello.cpp:149:44: 错误:从类型‘void (*)(tcp_stream*, void**)’到类型‘void*’的转换无效 [-fpermissive]
     nids_register_tcp(tcp_protocol_callback);       /*注册回调函数*/   
                                            ^
In file included from hello.cpp:1:0:
/usr/local/include/nids.h:149:6: 附注:initializing argument 1 of ‘void nids_register_tcp(void*)’
 void nids_register_tcp (void (*));

在nids.h中把头文件改了,或者把参数用(void*)强制转换

void nids_register_tcp (void (*));

修改头文件,改成如下声明,参考https://linux.die.net/man/3/libnids

void nids_register_tcp(void (*tcp_func)(struct tcp_stream *ts, void **param));

编译通过

//其他错误,x64系统下
编译命令:
#g++ -g tcp.cpp -o tcp -lpcap -lnet -lnids -lgthread-2.0
错误提示
#/usr/bin/ld: /usr/local/lib/gcc/x86_64-pc-linux-gnu/6.1.0/../../../libnids.a(libnids.o): undefined reference to symbol 'g_thread_exit'
/usr/lib64/libglib-2.0.so.0: error adding symbols: DSO missing from command line
collect2: 错误:ld 返回 1

正确方式:
#g++ -g tcp.cpp -o tcp -lpcap -lnet -lnids -lgthread-2.0 -lglib-2.0

二、Windows下编译使用libnids库

1、前期准备
目前网上的能稳定支持windows的libnids版本为libnids-W32-1.19。网上搜一下有很多,随便下一个并解压缩。由于libnids需要使用winpcap,所以要先下载并安装winpcap。到http://www.winpcap.org/install/default.htm下载最新版winpcap的安装包,然后到http://www.winpcap.org/devel.htm下载程序员开发包。安装winpcap。将libnids-W32-1.19的WIN32-Includes文件夹下文件存至另一个文件夹中(记为include文件夹)。将libnids-W32-1.19的WIN32-LIbraries文件夹下的库,和winpcap程序员开发包WpdPack文件夹中Lib文件夹中的Packet.lib和wpcap.lib放到一个文件夹中(记为lib文件夹)。

2、重新编译libnids库
在目录 WIN32-PRJ中,找到 libnids.dsw ,这个是6.0版本的,我用的是VS2015,打开,重新编译,生成libnids.lib,目前只要这个,把库移动到1中提到的lib文件夹下

3、测试libnids库
新建项目,加入测试代码如下:

#include 
#include "nids.h"
using namespace std;

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")
#pragma comment(lib, "libpcap.lib")
#pragma comment(lib, "libnids.lib")

#pragma warning(disable:4996)

//libnidsTest.cpp: 定义控制台应用程序的入口点。


char ascii_string[10000];
char*char_to_ascii(char ch)
/* 此函数的功能主要用于把协议数据进行显示 */
{
    memset(ascii_string, 0x00, 10000);
    char * string = ascii_string;

    if (ch >= 32 && ch <= 126)
    {
        *string++ = ch;
    }
    else if (ch == '\n' || ch == '\r')
    {
        *string++ = ch;
    }
    else
    {
        //其它字符以点"."表示
        *string++ = '.';
    }

    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;
    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_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连接被RST关闭 */
        printf("--------------------------------\n");
        printf("%sTCP连接被RST关闭\n", address_string);
        return;
    case NIDS_DATA:
        /* 表示有新的数据到达 */
    {
        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;
}
int main()
{
    nids_params.device = "3";
    if (!nids_init())
        /* Libnids初始化 */
    {
        printf("出现错误:%s\n", nids_errbuf);
        exit(1);
    }
    nids_register_tcp((void*)tcp_protocol_callback);
    /* 注册回调函数 */
    nids_run();
    /* Libnids进入循环捕获数据包状态 */
    return 0;
}

编译提示出错,大概如下

errorLNK2019: 无法解析的外部符号 "int __cdeclnids_init(void)" (?nids_init@@YAHXZ) ,该符号在函数 _main 中被引用 
errorLNK2001: 无法解析的外部符号 "char *nids_errbuf" (?nids_errbuf@@3PADA) 
errorLNK2001: 无法解析的外部符号 "structnids_prm nids_params" (?nids_params@@3Unids_prm@@A) 等错误

需要修改nids.h头文件,找到int nids_init ();一行,在该行前加上如下代码:

#ifdef __cplusplus
extern "C"{
#endif

在头文件尾加上

#ifdef __cplusplus
}
#endif

1.19的头文件最终改成如下

/*
  Copyright (c) 1999 Rafal Wojtczuk . All rights reserved.
  See the file COPYING for license details.
*/

#ifndef _NIDS_NIDS_H
#define _NIDS_NIDS_H
#define NIDS_MAJOR 1
#define NIDS_MINOR 19

#define NIDS_WIN32_PORTING "Goldie Rejuven checksum.org>"

#define NIDS_MINOR 19
#define NIDS_MAJOR 1
#define NIDS_MINOR 19

#ifdef WIN32
    #include 
    #include 
    #include 
    typedef unsigned int u_int;
    #define LIBNET_LIL_ENDIAN 1
#else
    #include 
#endif
#define HAVE_NEW_PCAP 0
enum
{
  NIDS_WARN_IP = 1,
  NIDS_WARN_TCP,
  NIDS_WARN_UDP,
  NIDS_WARN_SCAN
};

enum
{
  NIDS_WARN_UNDEFINED = 0,
  NIDS_WARN_IP_OVERSIZED,
  NIDS_WARN_IP_INVLIST,
  NIDS_WARN_IP_OVERLAP,
  NIDS_WARN_IP_HDR,
  NIDS_WARN_IP_SRR,
  NIDS_WARN_TCP_TOOMUCH,
  NIDS_WARN_TCP_HDR,
  NIDS_WARN_TCP_BIGQUEUE,
  NIDS_WARN_TCP_BADFLAGS
};


#define NIDS_JUST_EST 1
#define NIDS_DATA 2
#define NIDS_CLOSE 3
#define NIDS_RESET 4
#define NIDS_TIMED_OUT 5
#define NIDS_EXITING   6    /* nids is exiting; last chance to get data */

struct tuple4
{
  u_short source;
  u_short dest;
  u_int saddr;
  u_int daddr;
};

struct half_stream
{
  char state;
  char collect;
  char collect_urg;

  char *data;
  int offset;
  int count;
  int count_new;
  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;
  u_char urg_seen;
  u_int urg_ptr;
  u_short window;
  u_char ts_on;
  u_int curr_ts; 
  struct skbuff *list;
  struct skbuff *listtail;
};

struct tcp_stream
{
  struct tuple4 addr;
  char nids_state;
  struct lurker_node *listeners;
  struct half_stream client;
  struct half_stream server;
  struct tcp_stream *next_node;
  struct tcp_stream *prev_node;
  int hash_index;
  struct tcp_stream *next_time;
  struct tcp_stream *prev_time;
  int read;
  struct tcp_stream *next_free;
};

struct nids_prm
{
  int n_tcp_streams;
  int n_hosts;
  char *device;
  char *filename;
  int sk_buff_size;
  int dev_addon;
  void (*syslog) ();
  int syslog_level;
  int scan_num_hosts;
  int scan_delay;
  int scan_num_ports;
  void (*no_mem) (char *);
  int (*ip_filter) ();
  char *pcap_filter;
  int promisc;
  int one_loop_less;
  int pcap_timeout;
};

#ifdef __cplusplus
extern "C" {
#endif

int nids_init ();


void nids_register_ip_frag (void (*));
void nids_register_ip (void (*));
void nids_register_tcp (void (*));
void nids_register_udp (void (*));
void nids_killtcp (struct tcp_stream *);
void nids_discard (struct tcp_stream *, int);
void nids_run ();



int nids_getfd ();
int nids_next ();

#ifdef WIN32
int gettimeofday(struct timeval *tv,struct timezone *tz);
void *GetAdapterFromList(void* device,int index);

#define LOG_ALERT       1       /* action must be taken immediately */
#define LOG_LOCAL0      (16<<3) /* reserved for local use */
#define HAVE_BSD_UDPHDR 1
#define LITTLE_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#endif

extern struct nids_prm nids_params;
extern char *nids_warnings[];
extern char nids_errbuf[];
extern struct pcap_pkthdr *last_pcap_header;


#ifdef __cplusplus
}
#endif

#endif /* _NIDS_NIDS_H */

Libnids抓不到包的问题
运行后,如果出现一直抓不到数据包的情况,其实是网卡驱动没选好。所以我们在main()函数中第一行,添加一句代码:nids_params.device=”2”;将适配器设为真正起作用的设备。修改后的main()函数如下:

int main()
{
nids_params.device =”2”;

if(!nids_init())
{
printf(“出现错误:%s\n”, nids_errbuf);
exit(1);
}
printf(“初始化成功!\n”);
nids_register_tcp(tcp_protocol_callback);
nids_run();
}
如果还不行,就试试3、4…等等。

你可能感兴趣的:(libnids)