Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建

环境:ubuntu 16.04 64bit LTS 

下面的内容只是一些安装测试的步骤和方法的记录,并没有什么实质性和原理的说明,主要为作者本人记录的远程笔记,如果有幸对您也有帮助,请您顺手顶一下,如果您觉得您是在看不下去,也请不要喷我,毕竟学习不易,小白辛苦的学习还是需要鼓励的,先谢谢您呐!(滑稽狗头.jpg)

在项目中需要使用netfilter_queue修改数据包,然后习惯性的先找了度娘,看到了大神的博文 这是传送门 

但是奈何对这块的知识一点都不知道,环境也没有配置好,只能一点一点摸索,下面就当是自己的步骤做一个简单的记录。

个人习惯:习惯于将手动下载的,手动安装的程序放置在/opt下,所以操作都是在普通用户下使用sudo命令。

libnetfilter_queue主要依赖于libmnllibnfnetlink以及一些其他的工具等,先进行依赖文件的安装。

一、安装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

执行成功如图所示。

Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建_第1张图片

五、自己根据需要编写测试例程

测试例程功能简单说明:客户端和服务端通过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)即可。Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建_第2张图片

然后运行编译好的程序(代码后附)

sudo ./nfqueue 80

2、先运行服务端,然后再运行客户端进行连接并发送测试数据

客户端发送的数据

Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建_第3张图片

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

Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建_第4张图片

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

Linux -- 使用netfilter_queue修改数据包以及需要的环境搭建_第5张图片

下面是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);
}

如果感兴趣的话可以到去下载,整个测试的代码已经打包上传。下载传送门 如果作为兴趣但是不能下载,可以联系我,提供测试代码,为开源做贡献!

2020.01.13 补充更新:

        在一个老旧的机器上安装 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
注:在紧急使用状态下,此方案可以试一下,但是在正式场合不推荐使用的,毕竟有什么问题谁也不清楚。             

 

你可能感兴趣的:(Linux学习)