C语言 Linux中的应用协议过滤

y1aodyip  于 2023-04-29  发布在  Linux
关注(0)|答案(2)|浏览(112)

bounty还有2天到期。回答此问题可获得+100声望奖励。goodman希望引起更多关注这个问题。

我正试图在我的Linux机器上实现一个过滤不同层协议的迷你防火墙。到目前为止,我已经成功地使用Netfilter将数据包过滤到TCP层。然而,我现在正在尝试过滤应用程序协议(深度数据包检测),我面临着问题。
我尝试使用Netfilter来解析TCP/UDP有效载荷,但我无法获得数据包的内容,它总是将有效载荷显示为0,但在Wireshark中我可以看到一些数据。我想在数据包进入应用层之前对其进行过滤。
除了Netfilter之外,在Linux中是否还有其他方法可以用来过滤应用程序协议?
我试图获取HTTP数据的程序:Unable to parse HTTP packet using netfilter hooks in kernel module

9cbw7uwe

9cbw7uwe1#

我使用C语言中的libpcap来测试和编写这段代码,以捕获和过滤HTTP数据包。
在Linux(Ubuntu 20.04)首先安装libpcap:

sudo apt install libpcap-dev

下面是一个例子:

#include <stdio.h>
#include <pcap.h>

void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

int main(int argc, char *argv[]) {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle;
    struct bpf_program fp;
    bpf_u_int32 net, mask;

    // Step 1: Open the capture device
    handle = pcap_open_live("wlp5s0", BUFSIZ, 1, 1000, errbuf);
    if (handle == NULL) {
        fprintf(stderr, "Error opening device: %s\n", errbuf);
        return -1;
    }

    // Step 2: Compile and set the filter expression
    if (pcap_lookupnet("eth0", &net, &mask, errbuf) == -1) {
        fprintf(stderr, "Error getting netmask: %s\n", errbuf);
        net = 0;
        mask = 0;
    }

    if (pcap_compile(handle, &fp, "tcp port 80", 0, net) == -1) {
        fprintf(stderr, "Error compiling filter: %s\n", pcap_geterr(handle));
        return -1;
    }

    if (pcap_setfilter(handle, &fp) == -1) {
        fprintf(stderr, "Error setting filter: %s\n", pcap_geterr(handle));
        return -1;
    }

    // Step 3: Capture and process packets
    pcap_loop(handle, -1, process_packet, NULL);

    // Step 4: Cleanup
    pcap_freecode(&fp);
    pcap_close(handle);

    return 0;
}

void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
    printf("Received packet with length %d\n", header->len);

    // TODO: Parse the packet and extract the HTTP headers and content
}

注:

我勾选ifconfig -a,把wlp5s0,你可以添加eth0或其他。

nzk0hqpo

nzk0hqpo2#

我发现Wireshark能够解码HTTP数据包,这解释了为什么我可以在Wireshark中查看HTTP内容,但在我的程序中无法查看。因此,我将尝试从我的程序中解码HTTP,并更新代码以打印HTTP数据。

#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define PTCP_WATCH_PORT 80 /* HTTP port */

static struct nf_hook_ops nfho;
/* dump packet's data */
static void pkt_hex_dump(struct sk_buff *skb)
{
    size_t len;
    int rowsize = 16;
    int i, l, linelen, remaining;
    int li = 0;
    uint8_t *data, ch;
    struct iphdr *ip = (struct iphdr *)ip_hdr(skb);

    printk("Packet hex dump:\n");
    data = (uint8_t *)ip_hdr(skb);

    len = ntohs(ip->tot_len);

    remaining = len;
    for (i = 0; i < len; i += rowsize)
    {
        printk("%06d\t", li);
        linelen = min(remaining, rowsize);
        remaining -= rowsize;
        for (l = 0; l < linelen; l++)
        {
            ch = data[l];
            printk(KERN_CONT "%02X ", (uint32_t)ch);
        }
        data += linelen;
        li += 10;

        printk(KERN_CONT "\n");
    }
}
static unsigned int ptcp_hook_func(const struct nf_hook_ops *ops,
                                   struct sk_buff *skb,
                                   const struct net_device *in,
                                   const struct net_device *out,
                                   int (*okfn)(struct sk_buff *))
{
    struct iphdr *iph;   /* IPv4 header */
    struct tcphdr *tcph; /* TCP header */
    u16 sport, dport;    /* Source and destination ports */
    u32 saddr, daddr;    /* Source and destination addresses */

    /* Network packet is empty, seems like some problem occurred. Skip it */
    if (!skb)
        return NF_ACCEPT;

    iph = ip_hdr(skb); /* get IP header */

    /* Skip if it's not TCP packet */
    if (iph->protocol != IPPROTO_TCP)
        return NF_ACCEPT;

    tcph = tcp_hdr(skb); /* get TCP header */

    /* Convert network endianness to host endiannes */
    saddr = ntohl(iph->saddr);
    daddr = ntohl(iph->daddr);
    sport = ntohs(tcph->source);
    dport = ntohs(tcph->dest);

    /* Watch only port of interest */
    if (sport != PTCP_WATCH_PORT)
        return NF_ACCEPT;

    printk("print_tcp: %pI4h:%d -> %pI4h:%d\n", &saddr, sport,
           &daddr, dport);

    pkt_hex_dump(skb);

    return NF_ACCEPT;
}

static int __init ptcp_init(void)
{
    int res;

    nfho.hook = (nf_hookfn *)ptcp_hook_func; /* hook function */
    nfho.hooknum = NF_INET_PRE_ROUTING;      /* received packets */
    nfho.pf = PF_INET;                       /* IPv4 */
    nfho.priority = NF_IP_PRI_FIRST;         /* max hook priority */

    res = nf_register_net_hook(&init_net, &nfho);
    if (res < 0)
    {
        printk("print_tcp: error in nf_register_hook()\n");
        return res;
    }

    printk("print_tcp: loaded\n");
    return 0;
}

static void __exit ptcp_exit(void)
{
    nf_unregister_net_hook(&init_net, &nfho);
    printk("print_tcp: unloaded\n");
}

module_init(ptcp_init);
module_exit(ptcp_exit);

MODULE_DESCRIPTION("Module for printing HTTP packet data");
MODULE_LICENSE("GPL");

程序输出

wireshark日志:

相关问题