环境:ubuntu 16.04 64bit LTS
下面的内容只是一些安装测试的步骤和方法的记录,并没有什么实质性和原理的说明,主要为作者本人记录的远程笔记,如果有幸对您也有帮助,请您顺手顶一下,如果您觉得您是在看不下去,也请不要喷我,毕竟学习不易,小白辛苦的学习还是需要鼓励的,先谢谢您呐!(滑稽狗头.jpg)
在项目中需要使用netfilter_queue修改数据包,然后习惯性的先找了度娘,看到了大神的博文 这是传送门
但是奈何对这块的知识一点都不知道,环境也没有配置好,只能一点一点摸索,下面就当是自己的步骤做一个简单的记录。
个人习惯:习惯于将手动下载的,手动安装的程序放置在/opt下,所以操作都是在普通用户下使用sudo命令。
libnetfilter_queue主要依赖于libmnl,libnfnetlink以及一些其他的工具等,先进行依赖文件的安装。
一、安装libmnl
Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libmnl // 下载libmnl
Ubuntu@songshuai:/opt$ cd libmnl //完成之后进入到目录libmnl
Ubuntu@songshuai:/opt/libmnl$ sudo sh autogen.sh
在这个地方可能会出错,如果提示出现下面的错误
Ubuntu@songshuai:/opt/libmnl$ sudo sh autogen.sh
./autogen.sh: 3: ./autogen.sh: autoreconf: not found
是因为缺少系统工具autoconf,直接使用apt-get安装即可。
Ubuntu@songshuai:/opt/libmnl$ sudo apt-get install autoconf
继续进行,如果提示下面的错误
configure.ac:16: error: possibly undefined macro: AC_DISABLE_STATIC
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1
这是由于系统没有安装 libtool导致的,安装libtool
Ubuntu@songshuai:/opt/libmnl$ sudo apt-get install libtool
然后继续安装libmnl的操作
Ubuntu@songshuai:/opt/libmnl$ sudo ./autogen.sh
Ubuntu@songshuai:/opt/libmnl$ sudo ./configure
Ubuntu@songshuai:/opt/libmnl$ sudo make
Ubuntu@songshuai:/opt/libmnl$ sudo make install
完成。
二、安装 libnfnetlink
Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libnfnetlink
Ubuntu@songshuai:/opt$ cd libnfnetlink //进入到目录libnfnetlink
Ubuntu@songshuai:/opt/libnfnetlink$ sudo sh ./autogen.sh
Ubuntu@songshuai:/opt/libnfnetlink$ sudo ./configure
Ubuntu@songshuai:/opt/libnfnetlink$ sudo make
Ubuntu@songshuai:/opt/libnfnetlink$ sudo make install
顺利完成!
三、安装libnetfilter_queue
Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libnetfilter_queue
Ubuntu@songshuai:/opt$ cd libnetfilter_queue
Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo sh autogen.sh
Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo ./configure
Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo make
Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo make install
顺利完成!
四、测试
安装完成之后,进入到example目录,里面包含了一个测试文件,使用gcc编译并执行,因为例子中使用了libmnl的功能,所以编译需要连接libmnl。
Ubuntu@songshuai:/opt/libnetfilter_queue/example$ gcc nf-queue.c -o test -lmnl -lnetfilter_queue
在编译的过程可能会出现如下错误:
error while loading shared libraries: libnetfilter_queue.so.1: cannot open shared object file: No such file or directory
本人解决办法:
sudo ln -s /usr/local/lib/libnfnetlink.so.0 /lib/libnfnetlink.so.0
sudo ln -s /usr/local/lib/libnetfilter_queue.so.1 /lib/libnetfilter_queue.so.1
然后执行 test 文件进行测试
在测试之前需要将数据包入到队列中(本人测试中直接将所有的数据都入到队列8008中)
sudo iptables -I INPUT -j NFQUEUE --queue-num 8008
然后执行测试程序,起使用方式为./test queue_num
Ubuntu@songshuai:/opt/libnetfilter_queue/example$ sudo ./test 8008
在执行的时候可能或出现如下错误:
/usr/lib/x86_64-linux-gnu/libnfnetlink.so.0: no version information available (required by /lib/libnetfilter_queue.so.1)
本人解决办法:
export LD_LIBRARY_PATH=/usr/local/lib/
sudo ldconfig
执行成功如图所示。
五、自己根据需要编写测试例程
测试例程功能简单说明:客户端和服务端通过socket-tcp进行通讯,客户端只负责发送数据,服务端负责接收数据并显示,服务端通过iptables增加数据抓包并且修改其中的数据。
服务端iptables规则设置:
1、将所有输入的协议为tcp、目标端口为9999的数据入到队列号为80的队列
sudo iptables -I INPUT -p tcp --dport 9999 -j NFQUEUE --queue-num 80
可以使用指令查看是否插入成功。如果想要删除规则,则将指令中 -I (insert)换成 -D (delete)即可。
然后运行编译好的程序(代码后附)
sudo ./nfqueue 80
2、先运行服务端,然后再运行客户端进行连接并发送测试数据
客户端发送的数据
数据抓取成功并且更改成为其他的数据,然后发送到用户空间。
服务端运行成功并且接收到数据。
下面是nfqueue的主要实现的代码:
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data)
{
u_int32_t id = 0, i = 0;
u_int8_t* payload = NULL;
unsigned char *pdata = NULL;
int pdataLen = 0, length = 0;
struct nfqnl_msg_packet_hw *hwph = NULL;
struct nfqnl_msg_packet_hdr *ph = NULL;
struct tcphdr *tcphdrp = NULL;
struct udphdr *udphdrp = NULL;
struct iphdr *iphdrp = NULL;
uint16_t sport = 0, dport = 0;
char src_mac[sizeof("ff:ff:ff:ff:ff:ff\0")];
unsigned char tmp[1024] = {0};
// 提取数据包头信息,包括id,协议和hook点信息
ph = nfq_get_msg_packet_hdr(nfa);
if (ph) id = ntohl(ph->packet_id);
// 获取数据包载荷,data指针指向载荷,从实际的IP头开始
pdataLen = nfq_get_payload(nfa, ((unsigned char**)&pdata));
if(pdataLen == -1) pdataLen = 0;
iphdrp = (struct iphdr *)pdata;
// 获取到终端的大小数据
ioctl(STDIN_FILENO, TIOCGWINSZ, &size);
// 打印出和终端大小一样的框框
for(i = 0; i < size.ws_col; i++) printf("*");
printf("packet: %u, protocol = %u\n", id, iphdrp->protocol);
if(iphdrp->protocol == IPPROTO_TCP)
{
tcphdrp = (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
length = pdataLen - (iphdrp->ihl<<2) - (tcphdrp->doff<<2);
payload = (u_int8_t*)( (u_int8_t*)tcphdrp + (tcphdrp->doff<<2) );
sport = tcphdrp->source;
dport = tcphdrp->dest;
printf("len = %d\n", length);
/* 修改數據 */
for(i = 0; i < (length > 1024 ? 1024 : length); i++) tmp[i] = payload[length - 1];
memcpy(payload, tmp, length > 1024 ? 1024 : length);
}
else if(iphdrp->protocol == IPPROTO_UDP)
{
udphdrp = (struct udphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
length = pdataLen - (iphdrp->ihl<<2) - 8;
payload = (u_int8_t*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2) + 8);
sport = udphdrp->source;
dport = udphdrp->dest;
}
printf("line = %d, sport = %d, dport = %d\n", __LINE__, sport, dport);
/* 如果對數據報進行了修改,那麼必須進行校驗 */
set_ip_checksum(iphdrp);
if(iphdrp->protocol == IPPROTO_TCP) set_tcp_checksum1(iphdrp);
if(iphdrp->protocol == IPPROTO_UDP) set_udp_checksum1(iphdrp);
/* 打印出和终端大小一样的框框 */
for(i = 0; i < size.ws_col; i++) printf("*");
// 设置裁定
return nfq_set_verdict(qh, id, NF_ACCEPT, (u_int32_t)pdataLen, pdata);
}
如果感兴趣的话可以到去下载,整个测试的代码已经打包上传。下载传送门 如果作为兴趣但是不能下载,可以联系我,提供测试代码,为开源做贡献!
在一个老旧的机器上安装 libnetfilter_queue 出现如下问题:
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... no
checking whether compiler accepts -fvisibility=hidden... yes
./configure: line 12943: syntax error near unexpected token `LIBNFNETLINK,'
./configure: line 12943: `PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= 0.0.41)'
在网上查看解决,有牛人解答 这是传送门 但是实际上在我此处并没有效果,那么根据之前的安装环境,大概问题可能存在以下的几个地方
1、源的问题,我原先使用的时候阿里源,但是本次设置的机器的源为 ubuntu 默认源
2、在不更新源的情况下,重新手动下载新版本的 libnfnetlink 并安装,应该是没有问题(由于时间问题,没有尝试)
3、重新安装 libnfnetlink0 libnfnetlink-dev pkg-config
$ sudo apt-get install libnfnetlink0 libnfnetlink-dev pkg-config
4、不管3721,既然版本不够,那么直接修改最低版本,打开并编辑 configure.ac 文件
PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.41])
将 0.0.41 修改成 0.0.21
注:在紧急使用状态下,此方案可以试一下,但是在正式场合不推荐使用的,毕竟有什么问题谁也不清楚。