环境:ubuntu 16.04 64bit LTS
下面的内容只是一些安装测试的步骤和方法的记录,并没有什么实质性和原理的说明,主要为作者本人记录的远程笔记,如果有幸对您也有帮助,请您顺手顶一下,如果您觉得您是在看不下去,也请不要喷我,毕竟学习不易,小白辛苦的学习还是需要鼓励的,先谢谢您呐!(滑稽狗头.jpg)
在项目中需要使用netfilter_queue修改数据包,然后习惯性的先找了度娘,看到了大神的博文 这是传送门
但是奈何对这块的知识一点都不知道,环境也没有配置好,只能一点一点摸索,下面就当是自己的步骤做一个简单的记录。
个人习惯:习惯于将手动下载的,手动安装的程序放置在/opt下,所以操作都是在普通用户下使用sudo命令。
libnetfilter_queue主要依赖于libmnl,libnfnetlink以及一些其他的工具等,先进行依赖文件的安装。
一、安装libmnl
1 Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libmnl // 下载libmnl 2 Ubuntu@songshuai:/opt$ cd libmnl //完成之后进入到目录libmnl 3 Ubuntu@songshuai:/opt/libmnl$ sudo sh autogen.sh
在这个地方可能会出错,如果提示出现下面的错误
1 Ubuntu@songshuai:/opt/libmnl$ sudo sh autogen.sh 2 ./autogen.sh: 3: ./autogen.sh: autoreconf: not found
是因为缺少系统工具autoconf,直接使用apt-get安装即可。
1 Ubuntu@songshuai:/opt/libmnl$ sudo apt-get install autoconf
继续进行,如果提示下面的错误
1 configure.ac:16: error: possibly undefined macro: AC_DISABLE_STATIC 2 If this token and others are legitimate, please use m4_pattern_allow. 3 See the Autoconf documentation. 4 autoreconf: /usr/bin/autoconf failed with exit status: 1
这是由于系统没有安装 libtool导致的,安装libtool
1 Ubuntu@songshuai:/opt/libmnl$ sudo apt-get install libtool
然后继续安装libmnl的操作
1 Ubuntu@songshuai:/opt/libmnl$ sudo ./autogen.sh 2 Ubuntu@songshuai:/opt/libmnl$ sudo ./configure 3 Ubuntu@songshuai:/opt/libmnl$ sudo make 4 Ubuntu@songshuai:/opt/libmnl$ sudo make install
完成。
二、安装 libnfnetlink
1 Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libnfnetlink 2 Ubuntu@songshuai:/opt$ cd libnfnetlink //进入到目录libnfnetlink 3 Ubuntu@songshuai:/opt/libnfnetlink$ sudo sh ./autogen.sh 4 Ubuntu@songshuai:/opt/libnfnetlink$ sudo ./configure 5 Ubuntu@songshuai:/opt/libnfnetlink$ sudo make 6 Ubuntu@songshuai:/opt/libnfnetlink$ sudo make install
顺利完成!
三、安装libnetfilter_queue
1 Ubuntu@songshuai:/opt$ sudo git clone git://git.netfilter.org/libnetfilter_queue 2 Ubuntu@songshuai:/opt$ cd libnetfilter_queue 3 Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo sh autogen.sh 4 Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo ./configure 5 Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo make 6 Ubuntu@songshuai:/opt/libnetfilter_queue$ sudo make install
顺利完成!
四、测试
安装完成之后,进入到example目录,里面包含了一个测试文件,使用gcc编译并执行,因为例子中使用了libmnl的功能,所以编译需要连接libmnl。
1 Ubuntu@songshuai:/opt/libnetfilter_queue/example$ gcc nf-queue.c -o test -lmnl -lnetfilter_queue
在编译的过程可能会出现如下错误:
1 error while loading shared libraries: libnetfilter_queue.so.1: cannot open shared object file: No such file or directory
本人解决办法:
1 sudo ln -s /usr/local/lib/libnfnetlink.so.0 /lib/libnfnetlink.so.0 2 sudo ln -s /usr/local/lib/libnetfilter_queue.so.1 /lib/libnetfilter_queue.so.1
然后执行 test 文件进行测试
在测试之前需要将数据包入到队列中(本人测试中直接将所有的数据都入到队列8008中)
1 sudo iptables -I INPUT -j NFQUEUE --queue-num 8008
然后执行测试程序,起使用方式为./test queue_num
Ubuntu@songshuai:/opt/libnetfilter_queue/example$ sudo ./test 8008
在执行的时候可能或出现如下错误:
1 /usr/lib/x86_64-linux-gnu/libnfnetlink.so.0: no version information available (required by /lib/libnetfilter_queue.so.1)
本人解决办法:
1 export LD_LIBRARY_PATH=/usr/local/lib/ 2 sudo ldconfig
执行成功如图所示。

五、自己根据需要编写测试例程
测试例程功能简单说明:客户端和服务端通过socket-tcp进行通讯,客户端只负责发送数据,服务端负责接收数据并显示,服务端通过iptables增加数据抓包并且修改其中的数据。
服务端iptables规则设置:
1、将所有输入的协议为tcp、目标端口为9999的数据入到队列号为80的队列
1 sudo iptables -I INPUT -p tcp --dport 9999 -j NFQUEUE --queue-num 80
可以使用指令查看是否插入成功。如果想要删除规则,则将指令中 -I (insert)换成 -D (delete)即可。
然后运行编译好的程序(代码后附)
1 sudo ./nfqueue 80
2、先运行服务端,然后再运行客户端进行连接并发送测试数据
客户端发送的数据

数据抓取成功并且更改成为其他的数据,然后发送到用户空间。

服务端运行成功并且接收到数据。

下面是nfqueue的主要实现的代码:
1 static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) 2 { 3 u_int32_t id = 0, i = 0; 4 u_int8_t* payload = NULL; 5 unsigned char *pdata = NULL; 6 int pdataLen = 0, length = 0; 7 struct nfqnl_msg_packet_hw *hwph = NULL; 8 struct nfqnl_msg_packet_hdr *ph = NULL; 9 struct tcphdr *tcphdrp = NULL; 10 struct udphdr *udphdrp = NULL; 11 struct iphdr *iphdrp = NULL; 12 uint16_t sport = 0, dport = 0; 13 char src_mac[sizeof("ff:ff:ff:ff:ff:ff\0")]; 14 unsigned char tmp[1024] = {0}; 15 // 提取数据包头信息,包括id,协议和hook点信息 16 ph = nfq_get_msg_packet_hdr(nfa); 17 if (ph) id = ntohl(ph->packet_id); 18 // 获取数据包载荷,data指针指向载荷,从实际的IP头开始 19 pdataLen = nfq_get_payload(nfa, ((unsigned char**)&pdata)); 20 if(pdataLen == -1) pdataLen = 0; 21 iphdrp = (struct iphdr *)pdata; 22 // 获取到终端的大小数据 23 ioctl(STDIN_FILENO, TIOCGWINSZ, &size); 24 // 打印出和终端大小一样的框框 25 for(i = 0; i < size.ws_col; i++) printf("*"); 26 printf("packet: %u, protocol = %u\n", id, iphdrp->protocol); 27 28 if(iphdrp->protocol == IPPROTO_TCP) 29 { 30 tcphdrp = (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2)); 31 length = pdataLen - (iphdrp->ihl<<2) - (tcphdrp->doff<<2); 32 payload = (u_int8_t*)( (u_int8_t*)tcphdrp + (tcphdrp->doff<<2) ); 33 sport = tcphdrp->source; 34 dport = tcphdrp->dest; 35 printf("len = %d\n", length); 36 /* 修改數據 */ 37 for(i = 0; i < (length > 1024 ? 1024 : length); i++) tmp[i] = payload[length - 1]; 38 memcpy(payload, tmp, length > 1024 ? 1024 : length); 39 } 40 else if(iphdrp->protocol == IPPROTO_UDP) 41 { 42 udphdrp = (struct udphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2)); 43 length = pdataLen - (iphdrp->ihl<<2) - 8; 44 payload = (u_int8_t*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2) + 8); 45 sport = udphdrp->source; 46 dport = udphdrp->dest; 47 } 48 printf("line = %d, sport = %d, dport = %d\n", __LINE__, sport, dport); 49 51 /* 如果對數據報進行了修改,那麼必須進行校驗 */ 52 set_ip_checksum(iphdrp); 53 if(iphdrp->protocol == IPPROTO_TCP) set_tcp_checksum1(iphdrp); 54 if(iphdrp->protocol == IPPROTO_UDP) set_udp_checksum1(iphdrp); 55 /* 打印出和终端大小一样的框框 */ 56 for(i = 0; i < size.ws_col; i++) printf("*"); 57 // 设置裁定 58 return nfq_set_verdict(qh, id, NF_ACCEPT, (u_int32_t)pdataLen, pdata); 59 }
如果感兴趣的话可以到去下载,整个测试的代码已经打包上传。下载传送门 如果作为兴趣但是不能下载,可以联系我,提供测试代码,为开源做贡献!
