Snort源代码编译 _ 采坑之旅(for Windows VS2015)

    系统环境:Windows7 sp1 x64
    编译环境:VS2015 SP1
    Snort版本:2.9.12
    daq版本:2.0.6
    Snort官网:https://www.snort.org/downloads#snort-downloads


背景

    最近需要实现一个类似网络防火墙的产品,主要参考Snort源码,先花了点时间简单读了下网上比较流行的《snort源码分析》里面的资料,然后对着源码瞅了下,发现从snort2.9开始,snort应该是重构过了一轮,导致网上的资料都是偏老的,前人的一些源码分析都是基于2.9之前的版本的。我们的目标是先把源码在Windows平台上面编译通过,能调试!


注意事项

    0、开始之前……
    1、大家读源码的时候,如果发现网上的分析资料有些出入,应该就是重构导致的,最大的重构就是daq被当成一个静态lib剥离出来了,这块下层跟wibpcap/libpcap交互,上层跟snort交互的一个中间层的,之前这块的逻辑是跟snort本身糅合在一起的。
    2、Snort的源码大量基于另外的第三方源码,需要安装cygwin(主要是头文件依赖和bison.exe等工具依赖)。cygwin固定安装到C:\cygwin,并且手动把bison、flex、sed这三个开源库安装上(为啥装这个三个开源库也是参考网上了说法,实际使用中,目前只看到使用了bison),另外就是安装cygwin的时候如果在下载阶段有问题,可以使用163的镜像http://mirrors.163.com/.help/cygwin.html。
    3、网上流传最多的就是独孤九贱的源码分析,但是一般只有7章,我这里有个完整的版本(https://download.csdn.net/download/magictong/10859695),可以参考下,不过这个源码分析是基于2.2版本的。


编译采坑之旅

    注意:
    a、50%是解决与VS2015的兼容性问题
    b、有些比较明显的问题,就不提了,譬如netinet/in.h这种明显是linux下面的头文件但是没有包含在#ifndef WIN32里面,譬如编译选项冲突,譬如文件缺失找不到等等
    c、编译参考(注:这篇文章里面是用VS2013编译的,坑没有VS2015多):https://blog.csdn.net/feixi7358/article/details/79817604

0、in6_addr以及相关定义冲突问题,这个是最大的坑。
原因:原因就是开源库和微软VS(in6addr.h)对于in6_addr定义是冲突,联合体里面有些字段的名字不一样的,这个问题要解决还挺麻烦的,不过有个简单的方法就是修改VS的公共头文件(解决方案里面增加红字部分),看起来有些不优雅,不过实际上没有问题,因为是一个联合体,并不会改变结构的内存结构。
解决方案:
//
// IPv6 Internet address (RFC 2553)
// This is an 'on-wire' format structure.
//
typedef struct in6_addr {
    union {
        UCHAR       Byte[16];
        USHORT      Word[8];
        UCHAR       u6_addr8[16];
        USHORT      u6_addr16[8];
        UINT            u6_addr32[4];

    } u;
} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;

1、fatal error C1189: #error: Macro definition of snprintf conflicts with Standard Library function declaration
原因:有很多的开源库或者程序将 snprintf 函数定义为 _snprintf,而微软在VS2015出现之前并不支持_snprintf,然而,微软从VS2015开始定义 snprintf,当然微软也想到了这个问题,因此给出了这么一个还算是人性化的错误提示。
Reference:https://blog.csdn.net/A1367297309/article/details/52997312
解决方案:
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif

2、reload_api.h打不开(#include "reload_api.h")
原因:MSBuildTool拷贝时遗漏了文件。
解决方案:找到reload_api.h拷贝到snort-2.9.12\src\dynamic-preprocessors\include下即可。

3、ip6_hops重定义
原因:定义多份,而且含义不一样,实际上ip6_hops从来没用过。
解决方案:可以注释掉
// #define ip6_hops         hop_limit
// #define ip6_hops  ip6_ctlun.ip6_un1.ip6_un1_hlim

4、Warning太多,建议屏蔽部分
#ifdef WIN32
#pragma warning(disable: 4996 4293 4334 4018 4244)
#endif

5、下面这个问题比较明显,提示%s和后面的dlerror()的返回值不匹配。
#ifdef WIN32
        fprintf(stderr, "%s: %s: %u\n", filename, dlsym_func_name, dlerror());
#else
        fprintf(stderr, "%s: %s: %s\n", filename, dlsym_func_name, dlerror());
#endif

6、关掉SafeSEH:No (/SAFESEH:NO)

7、将\snort-2.9.11.1\src\中的 reload.c/.h 和 pkt_tracer.c/.h 添加到snort项目中。

8、拷贝:reg_test.h到snort-2.9.12\src\dynamic-preprocessors\include

9、拷贝:preprocids.h到snort-2.9.12\src\dynamic-plugins\sf_engine

10、改造:max提示错误
原因:Windows下宏冲突
解决方案:
#ifndef WIN32
static uint32_t max(uint32_t a, uint32_t b)
{
    if (a >= b)
        return a;
    return b;
}
#endif // !WIN32

11、dnet.lib里面提示无法解析外部符号__imp___snprintf,_sprintf等(VS2015的深坑)
2>dnet.lib(intf-win32.obj) : error LNK2019: unresolved external symbol __imp___snprintf referenced in function __ifrow_to_entry
2>dnet.lib(addr-util.obj) : warning LNK4217: locally defined symbol _sprintf imported in function _ip6_ntop
2>dnet.lib(addr.obj) : warning LNK4049: locally defined symbol _sprintf imported
Reference:https://stackoverflow.com/questions/32418766/c-unresolved-external-symbol-sprintf-and-sscanf-in-visual-studio-2015#comment52704958_32418900
解决方案:
#ifdef WIN32
#if defined(_MSC_VER) && _MSC_VER >= 1900
#pragma comment(lib, "legacy_stdio_definitions.lib")
#endif
#endif


12、VS2015再踩一坑:无法识别的外部符号 __imp__iob,__imp__pctype,__imp___mb_cur_max
Reference:
https://blog.csdn.net/travis_bacon/article/details/80017844
https://stackoverflow.com/questions/31546519/visual-studio-15-imp-iob-imp-pctype-imp-mb-cur-max
解决方案:
#ifdef WIN32
#if defined(_MSC_VER) && _MSC_VER >= 1900
#pragma comment(lib, "libmsvcrt.a")
#endif
#endif

上面的这个方法随便编译链接成功,但是有一堆的问题,后面是用下面的方法曲线救国:

#undef __mb_cur_max
int __cdecl __mb_cur_max(void)
{
    return ___mb_cur_max_func();
}

#undef _pctype
const unsigned short* __cdecl _pctype(void)
{
    return __pctype_func();
}

13、又来一个:unresolved external symbol __imp__pthread_mutex_unlock
Reference:
https://stackoverflow.com/questions/13803795/pthread-mutex-error-lnk2019-unresolved-external-symbol-c
https://www.sourceware.org/pthreads-win32/
解决方案:pthreadVC2.lib pthreadVC2.dll
//////////////////////////////////////////////////////////////////////////
// VS2015之后很多stdio里面函数改成了inline链接
// Add by Magictong 2018/12/18 15:43:52
// 
#ifdef WIN32
#if defined(_MSC_VER) && _MSC_VER >= 1900
#pragma comment(lib, "legacy_stdio_definitions.lib")
#pragma comment(lib, "libmsvcrt.a")
#pragma comment(lib, "pthreadVC2.lib")
#endif
#endif
//////////////////////////////////////////////////////////////////////////

 

Tips

    另外,读源码的时候,根据我的个人经验[酷]
    1、在不能调试的情况下,看开源代码的时候,不要从开头什么类似main函数看下去,否则很可能被淹没在庞大的代码里面(其实调试也一样,如果没有找到关键点,调试也是抓瞎)。
    2、对于我们感兴趣的功能点,直接针对的性的去看,带着目标去看,把相关功能的接口理清晰,搞明白。然后再设定下一个小目标,反复进行。
    3、有些中间的结论,及时的画一画,写下来,否则很容易忘记。很多开源代码写得都很天马行空。

你可能感兴趣的:(C++,Win32,Snort,Snort编译,Snort,for,win32)