本文为原创。转载请注明:
作者:Utensil
博客:http://utensil.iteye.com/
邮箱:utensilcandel@gmail.com
鉴于网上存在两个libnet,本文中所谓libnet是指位于http://www.packetfactory.net/libnet/
的The Libnet Packet Construction Library。
libnet是一个小型的接口函数库,主要用C语言写成,提供了低层网络数据报的构造、处理和发送功能。libnet的开发目的是:建立一个简单统一的网络编程接口以屏蔽不同操作系统低层网络编程的差别,使得程序员将精力集中在解决关键问题上。它的主要特点是:
- 高层接口:libnet主要用C语言写成。
- 可移植性:libnet目前可以在Linux、FreeBSD、Solaris、WindowsNT等操作系统上运行,并且提供了统一的接口。
- 数据报构造:libnet提供了一系列的TCP/IP数据报文的构造函数以方便用户使用。
- 数据报的处理:libnet提供了一系列的辅助函数,利用这些辅助函数,帮助用户简化那些烦琐的事务性的编程工作。
- 数据报发送:libnet允许用户在两种不同的数据报发送方法中选择。
另外libnet允许程序获得对数据报的绝对的控制,其中一些是传统的网络程序接口所不提供的。这也是libnet的魅力之一。
详细介绍可参见《使用libnet与libpcap构造TCP/IP协议软件》(http://www.ibm.com/developerworks/cn/linux/l-tcpip/
)。
本来看到libnet源代码树根目录中的configure脚本,我以为只需要在MSYS下键入configure然后make就可以了。谁料断断
续续折腾了几个星期,根据gcc的出错信息强行修改了十余处源代码,才使其编译通过,却又遭遇大量链接出错,实在令人气馁。今天决心从问题的根源下手,终
于用一个比原先简洁得多的修改方案使其通过编译和链接,特写此博客予以记述。
基本前提
正确下载和安装MinGW和MSYS,假设分别位于C:\MinGW和C:\msys。(下载地址:http://sourceforge.net/project/showfiles.php?group_id=2435
)
准备工作
1)从http://www.packetfactory.net/libnet/dist/
下载libnet的源代码。我选择的文件是libnet-1.1.3-RC-01.tar.gz
。解压。将其内容复制到D:\libnet,注意,此操作的结果应使D:\libnet下有include、src等子文件夹。也可自选其它位置,本文按D:\libnet进行叙述。
2)因为libnet依赖于libpcap,所以要从http://www.winpcap.org/devel.htm
下
载Developer's
Pack。我选择的是4.0.2。解压。将Include子文件夹中的文件复制到D:\libnet\include。Gnuc.h文件会冲突,这无关紧
要,我选择保留libnet自己那个。将Lib子文件夹中的文件复制到D:\libnet\lib(原来没有这个文件夹的,自己建)。
3)试着编译一下:在msys中
cd /d/libnet
./configure
make
如果configure出错,说明MinGW或MSYS安装不正确。可能是没有将C:\MinGW\bin加入PATH,修改C:\msys\profile,在
if [ $MSYSTEM == MINGW32 ]; then
export PATH=".:/usr/local/bin:/mingw/bin:/bin:$PATH"
else
export PATH=".:/usr/local/bin:/bin:/mingw/bin:$PATH"
fi
后面加上:
export PATH=
"/c/MinGW/bin:$PATH"
其它错误类型本文不予考虑。
如果make出错,这属于正常,除非它说的是找不到pcap.h,这样的话,请检查第二步做对没有。
读者可自行尝试修正其错误,也可按照下面这个简洁方案。
4)顺便介绍一下如何察看MinGW的预定义宏:
gcc -dM -E - < nul
这个命令在处理跨平台和移植性问题时相当有用。比如从它的输出可以看出,_WIN32、__WIN32__、__MINGW32__等宏已经被定义,这样,面对那些基于这些宏的预处理语句,就有一个清晰些的思路,不用去猜。
修改方案
1)修改include/win32/libnet.h为:
#if (__MINGW32__)
#include "pcap.h"
#define HAVE_NET_ETHERNET_H 0
#include "../libnet.h"
#include <wincrypt.h>
#else
原来文件内容
#endif
观察第4行,这是把编译器导引回去读include/libnet.h,那个头文件是为UNIX-Like系统写的,也是最初的头文件,Linux
下或Cygwin下都用它,没什么问题。本文件(include/win32/libnet.h)是为VC写的,由于libnet没有被官方地移植到
MinGW,在src/*.c文件中,把又是Win32又不是Cygwin的情况都按照是VC处理了。结果MinGW被牛头不对马嘴地安上了只适合VC的
头文件,自然会出问题了。但是include/libnet.h也不是直接就能用,需要进行一些微调。这里面几个语句的顺序非常重要。
2)修改include/libnet-functions.h中函数libnet_open_raw4(libnet_t *l);前的
#if ((__WIN32__) && !(__CYGWIN__))
为
#if ((__WIN32__) && !(__CYGWIN__)) && !(__MINGW32__)
3)修改src/libnet_link_none.c为
#if (__MINGW32__)
#include "libnet_link_win32.c"
#else
原文件内容
#endif
此处修改是权宜之计,因为不知为什么,libnet_link_win32.c没有被编译,却把没做任何事的libnet_link_none给编译了。与其去研究Makefile,不如来个调包。
4)此时编译可通过。然而出现大量undefined reference这种链接错误。修改之前make过程生成的src/libnet.la中的
dependency_libs=
''
为
dependency_libs=
'-lwsock32 -lws2_32 -liphlpapi -L/d/libnet/lib -lwpcap -lpacket'
注意,其中-L/d/libnet/lib一项,是叫gcc到D:\libnet\lib去寻找libwpcap.a和libpacket.a。要根据你自己放置它们的位置进行调整。
此时链接会成功,但编译到例子get_addr.c时,出现错误undefined reference to
'_imp__optarg'。这样libnet就成功编译了。例子之所以出错,是因为它使用了getopt来处理例子中需要处理的命令行参数,而该函数
在MinGW似乎有可移植性问题,MinGW mailing
list上有一个人在2006年问了这个问题怎么解决,到现在还没有人答他。所幸这个问题不影响libnet库本身。
此时你会在src/.lib下发现编译好的libnet.a。大小为19M多,是静态库。
5)顺便介绍一下怎么察看里面的函数:
nm -g --defined-only --demangle libnet.a
测试例程
这个例程修改自arp.c和libpcap的例子basic_dump.c
#include <stdio.h>
#include <stdlib.h>
#include "../sample/libnet_test.h"
int
main(int argc, char *argv[])
{
int c;
u_int32_t i;
libnet_t *l;
libnet_ptag_t t;
char *device = NULL;
u_int8_t *packet;
u_int32_t packet_s;
char errbuf[LIBNET_ERRBUF_SIZE];
printf("libnet 1.1 packet shaping: ARP[link -- autobuilding ethernet]\n");
if (argc > 1)
{
device = argv[1];
}
else
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
/* Retrieve the device list */
if(pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
device = d->name;
}
l = libnet_init(
LIBNET_LINK_ADV, /* injection type */
device, /* network interface */
errbuf); /* errbuf */
if (l == NULL)
{
fprintf(stderr, "%s", errbuf);
exit(EXIT_FAILURE);
}
else
i = libnet_get_ipaddr4(l);
t = libnet_build_arp(
ARPHRD_ETHER, /* hardware addr */
ETHERTYPE_IP, /* protocol addr */
6, /* hardware addr size */
4, /* protocol addr size */
ARPOP_REPLY, /* operation type */
enet_src, /* sender hardware addr */
(u_int8_t *)&i, /* sender protocol addr */
enet_dst, /* target hardware addr */
(u_int8_t *)&i, /* target protocol addr */
NULL, /* payload */
0, /* payload size */
l, /* libnet context */
0); /* libnet id */
if (t == -1)
{
fprintf(stderr, "Can't build ARP header: %s\n", libnet_geterror(l));
goto bad;
}
t = libnet_autobuild_ethernet(
enet_dst, /* ethernet destination */
ETHERTYPE_ARP, /* protocol type */
l); /* libnet handle */
if (t == -1)
{
fprintf(stderr, "Can't build ethernet header: %s\n",
libnet_geterror(l));
goto bad;
}
if (libnet_adv_cull_packet(l, &packet, &packet_s) == -1)
{
fprintf(stderr, "%s", libnet_geterror(l));
}
else
{
fprintf(stderr, "packet size: %d\n", packet_s);
libnet_adv_free_packet(l, packet);
}
c = libnet_write(l);
if (c == -1)
{
fprintf(stderr, "Write error: %s\n", libnet_geterror(l));
goto bad;
}
else
{
fprintf(stderr, "Wrote %d byte ARP packet from context \"%s\"; "
"check the wire.\n", c, libnet_cq_getlabel(l));
}
libnet_destroy(l);
return (EXIT_SUCCESS);
bad:
libnet_destroy(l);
return (EXIT_FAILURE);
}
/* EOF */
设置注意事项:
1)环境变量:对编译器,要添加:D:\libnet\include;对连接器,要添加D:\libnet\lib和D:\libnet\src\.libs
2)链接的库:(按顺序)libnet.a libpacket.a libwpcap.a libiphlpapi.a libws2_32.a libwsock32.a
3)运行此程序,运行所有WinPcap的程序一样,要下载并安装WinPcap(http://www.winpcap.org/install/default.htm
)。
分享到:
相关推荐
如果你在项目中链接了libnet.lib,编译器会将libnet库的代码合并到你的可执行文件中,这样就不需要在目标机器上安装libnet.dll也能运行程序。静态链接的可执行文件自包含且独立,但生成的文件通常较大,因为包含了库...
2. 将libnet.lib(静态库)链接到你的项目中,或者将libnet.dll(动态库)放在系统路径下或应用程序同目录。 3. 引入libnet头文件,例如`#include <libnet.h>`。 4. 使用libnet提供的API,如libnet_init_packet()...
5. **数据包注入**: libnet 允许开发者直接将数据包注入到网络链路层,绕过操作系统内核的网络栈,这对于进行网络渗透测试、安全研究或者开发网络工具非常有用。 6. **动态内存管理**: 库内部实现了动态内存管理,...
libnet与libpcap和libnids并称为网络安全开发的三大法宝,它们共同为开发者提供了丰富的API,帮助他们编写出结构良好、性能稳定且具有高度可移植性的程序。 #### 二、libnet的特点 1. **高级别的抽象**: libnet...
3. **添加源文件**:将libnet源代码中的所有.c和.h文件添加到项目中。通常,这些文件位于`src`目录下,包括`libnet.c`和`libnet.h`等。 4. **配置编译选项**:在项目属性中,转到“配置属性”> “C/C++”> “常规”...
3. **ARP攻击**:ARP(Address Resolution Protocol)是一种用于将IP地址映射到物理MAC地址的协议。在描述中提到的两个源代码文件`arp中间人欺骗.c`和`arpattack.c`,可能包含实现ARP中间人攻击的代码。ARP中间人...
"对应库文件生成目录:libnet-libnet-1.2-rc3\libnet\src" 指明了生成的库文件和源代码所在的目录结构,这将有助于开发者找到和使用这些文件。 **标签解析:** "libnet网络库" 标签明确了libnet是一个专用于网络...
这个资源,"LibnetNT-src.zip_libnet_libnet.zip_libnetNt source code",是将Libnet库移植到Windows(Win32)系统上的成果。这对于Windows开发者来说,无疑是一个极具价值的工具,因为它允许在Windows平台上进行...
2. **静态链接库(LIB)**:静态链接库将库代码直接合并到最终的可执行文件中,程序运行时不需要DLL,但会使可执行文件体积增大,不便于更新库。 3. **libnet库**:可能包含网络协议构造、网络扫描、嗅探、攻击等...
3. **网络数据包发送**:libnet允许开发者将构造好的数据包直接发送到网络,而不依赖于高层的应用层协议,如TCP或UDP。这在低级网络测试、漏洞探测或特殊网络应用中很有价值。 4. **C语言编程**:了解C语言基础是...
2. **数据包发送**:libnet提供API接口,允许开发者将构造好的数据包发送到指定的网络接口或者IP地址。 3. **错误处理**:libnet内置了丰富的错误检查和报告机制,当出现错误时,可以准确地定位问题所在。 4. **多...
这里提到的".tar.gz"是一个常见的Linux/Unix系统中的文件压缩格式,它使用tar工具将多个文件打包,并用gzip压缩,方便下载和存储。"编译完成版"表示这个libnet库的源代码已经被成功编译为可执行形式。"debug中有dll...
它为开发者提供了构建各种网络协议头的能力,如TCP/IP,UDP等,并能将这些数据包发送到目标网络接口,这对于网络编程和安全研究非常有用。这个库主要适用于Linux操作系统,因为Linux系统提供了一个开放的环境,允许...
3. **函数接口:** Libnet 提供了诸如 `libnet_init_packet()`(初始化数据包)、`libnet_write()`(写入数据到包中)、`libnet_insert_XX()`(插入特定协议字段)和 `libnet_apply_checksum()`(计算校验和)等函数...
- **配置项目设置**:在VS2010中,需要将libnet库添加到项目的链接器设置中,确保编译器能找到所需的库文件。 - **头文件包含**:在源代码中包含libnet的头文件,如`#include <libnet.h>`,以使用其提供的接口。 ...
- **添加负载**:`libnet_write()`函数用于将用户数据添加到数据包中。 - **校验和计算**:Libnet会自动处理校验和的计算,确保数据包的正确性。 - **发送数据包**:最后,`libnetInjection()`函数用于将构造好的...
3. **发送数据包**:构造好数据包后,通过libnet的发送函数将其发送到网络上。 #### 四、libnetNT及其使用方法 **4.1 libnetNT简介** libnetNT是libnet在Windows NT/2000下的版本。为了在Windows平台上使用...
- 最后,执行`make install`将编译好的库安装到系统指定的目录。 4. **使用示例** `examples`目录中的程序展示了如何使用libnet发送简单的TCP和UDP数据包。例如,`ping6.c`是一个IPv6 ping程序,它使用libnet构建...
Heartbeat是Linux HA项目的一部分,是一个轻量级的网络通信服务,主要负责监控系统状态并在主服务器失效时将控制权转移到备份服务器。它通过网络心跳检测来确认服务器的状态,当主服务器无法响应心跳时,Heartbeat会...
3. 发送数据包:调用libnet_write()将数据包发送到网络。 4. 错误处理:定期检查libnet_geterror()返回的错误码,处理可能出现的问题。 5. 清理:完成工作后,调用libnet_destroy()释放资源。 五、libnet源代码分析...