iptables queue 应用示例

40 篇文章 11 订阅
3 篇文章 0 订阅

简介

Linux内核在Netfilter框架的基础上提供了IP Queue机制,从而使得基于用户态的防火墙开发成为可能。从而可以在用户态对报文内容进行分析,同时可以给出对这个报文的处理意见,也可以修改报文。
libipq是基于netfilter提供的接口进行二次封装的库,目的是让大家能够更多专注于用户态的数据处理,简化用户态和内核态数据交换流程。

环境依赖

需要安装libnetfilter_queue,libnetfilter_queue-devel,iptables,iptables-devel

yum install -y libnetfilter_queue libnetfilter_queue-devel iptables iptables-devel

头文件

#include <linux/netfilter.h>
#include <libipq.h>

示例

ipq_test.c

/*
 *  * This code is GPL.
 *   */
#include <linux/netfilter.h>
#include <libipq.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 2048 

static void die(struct ipq_handle *h)
{
    ipq_perror("passer");
    ipq_destroy_handle(h);
    exit(1);
}

int main(int argc, char **argv)
{
    int status;
    unsigned char buf[BUFSIZE];
    struct ipq_handle *h;
    
    // 创建handle,用于数据传输,NFPROTO_IPV4指ipv4的协议
    h = ipq_create_handle(0, NFPROTO_IPV4);
    if (!h)
        die(h);

    // 设置传递元数据和原始报文到用户态
    status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
    if (status < 0)
        die(h);

    do{
        // 读取数据包
        status = ipq_read(h, buf, BUFSIZE, 0);
        if (status < 0)
            die(h);
       
        // 判断数据包类型,类型IPQM_PACKET代表通过queue传过来的数据包
        switch (ipq_message_type(buf)) {
            case NLMSG_ERROR:
                fprintf(stderr, "Received error message %d\n",
                        ipq_get_msgerr(buf));
                break;

            case IPQM_PACKET: 
                {
                    // 获取数据包,包含元数据(包摘要)和原始数据包
                    ipq_packet_msg_t *m = ipq_get_packet(buf);

                    /* 将处理结果发到内核,内核根据结果进行处理
                    *  NF_ACCEPT表示接收数据
                    */
                    status = ipq_set_verdict(h, m->packet_id,
                            NF_ACCEPT, 0, NULL);
                    if (status < 0)
                        die(h);
                    break;
                }


            default:
                fprintf(stderr, "Unknown message type!\n");
                break;
        }
    } while (1);

    // 释放资源
    ipq_destroy_handle(h);
    return 0;
}

  • ipq_create_handle(0, NFPROTO_IPV6)
    创建handle, 第1个参数目前没有用到,直接设置为0。第2个参数表示要接收的数据包类型,主要有下面几种:
    • NFPROTO_UNSPEC = 0,
    • NFPROTO_IPV4 = 2,
    • NFPROTO_ARP = 3,
    • NFPROTO_BRIDGE = 7,
    • NFPROTO_IPV6 = 10,
    • NFPROTO_DECNET = 12,
  • ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE)
    设置队列模式,模式有下面几种:
    • IPQ_COPY_NONE, 报文将被丢弃
    • IPQ_COPY_META, 内核将在其后的报文传递中只传递“报文的元数据”
    • IPQ_COPY_PACKET 内核将同时传递“报文的元数据”和报文本身,报文本身的传递长度由BUFSIZE指定。 BUFSIZE的最大值不能超过IP报文的最大长度,也就是0xFFFF。如果请求的长度大于报文自身的长度,将会按照报文自身长度进行传递。
  • ipq_read(h, buf, BUFSIZE, 0)
    通过h读取queue中的数据到buf指向的内存中,最大长度为BUFSIZE,第4个参数表示超时时间,单位是微秒,0表示不超时。
  • ipq_message_type(buf)
    判断数据包类型,返回IPQM_PACKET表示内核传到queue中的数据。
  • ipq_get_packet(buf)
    从buf中获取数据包,这里返回的是ipq_packet_msg_t结构
typedef struct ipq_packet_msg {
    unsigned long packet_id;    /* 数据包id */
    unsigned long mark;     /* Netfilter mark value */
    long timestamp_sec;     /* 收包时间 (秒) */
    long timestamp_usec;        /* 收包时间 (微秒) */
    unsigned int hook;      /* 钩子在netfilter上挂载的位置 */
    char indev_name[IFNAMSIZ];  /* Name of incoming interface */
    char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */
    __be16 hw_protocol;     /* Hardware protocol (network order) */
    unsigned short hw_type;     /* Hardware type */
    unsigned char hw_addrlen;   /* Hardware address length */
    unsigned char hw_addr[8];   /* Hardware address */
    size_t data_len;        /* Length of packet data */
    unsigned char payload[0];   /* 这里指向原始数据包 */
} ipq_packet_msg_t;
  • ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 0, NULL)
    发送处理结果给内核,主要有如下几种:
    NF_DROP: 丢弃该报文,释放所有与该报文相关的资源;
    NF_ACCEPT: 接受该报文,并继续处理;
    NF_STOLEN: 该报文已经被HOOK函数接管,协议栈无须继续处理;
    NF_QUEUE: 将该报文传递到用户态去做进一步的处理;
    NF_REPEAT: 再次调用本HOOK函数。
    NF_STOP : 与NF_ACCEPT类似但强于NF_ACCEPT,一旦挂接链表中某个hook节点返回NF_STOP,该skb包就立即结束检查而接受,不再进入链表中后续的hook节点,而NF_ACCEPT则还需要进入后续hook点检查。
  • ipq_destroy_handle(h)
    释放handle资源。

测试

编译

gcc ipq_test.c -o ipqtest -lipq

导入模块

需要导入iptable_filter和ip_queue模块

modprobe iptable_filter
modprobe ip_queue

配置iptables规则

在用户态对数据包进行处理,需要配置iptables规则,将符合条件的数据包转到netfilter提供的queue中。

iptables -A INPUT -p icmp -j QUEUE

如果是ipv6的数据包,需要使用ip6tables来配置规则

ping本机loopback地址

 ping 127.0.0.1

此时没有数据包回复
在这里插入图片描述

启动ipqtest程序

./ipqtest 

此时ping包能够收到回复数据
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高晓伟_Steven

相逢即是有缘,动力源于金钱。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值