c - 将数据添加到特定协议(protocol)的数据包中

标签 c networking kernel-module netfilter

我正在实现一个名为 XOR 的新协议(protocol)。首先,数据包在用户空间中创建并发送到网络。之后数据包正常到达网络中的其他节点。现在我需要创建一个模块来拦截发送的每个模块并添加 header 或一些数据。我创建了一个模块,将一些数据放入数据包中,但没有成功。

我尝试了一些方法,但是当激活我的模块时,数据包被丢弃。这就是我的模块正在做的事情:

struct xorhdr {
    int in;
    int out;
};

static unsigned int asnfwd_hook(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;
    struct asnfwd_opt *opt;
    __be32 addr = 0;
    struct tcphdr *th;
    struct udphdr *uh;

    /* sanity check */
    if (!skb)
        goto accept;

    /* recover the IPv4 header */
    iph = ip_hdr(skb);
    if (!iph)
        goto accept;

    if (iph->protocol == 17) {
        uh = (struct udphdr *) skb_transport_header(skb);
        if ((unsigned int) ntohs(uh->source) == XOR_PORT && (unsigned int) ntohs(uh->dest) == XOR_PORT) {
            printk("\n****************************\n");
            printk("Hook is %s\n", (in ? "pre-routing" : "local-out"));
            printk("(Ogirinal) From %pI4 to %pI4.\n", &iph->saddr, &iph->daddr);
            printk(KERN_INFO "free:%d", skb_headroom(skb));

            if (in) {
                struct xorhdr *ptr;

                if (skb->tail + sizeof(struct xorhdr) < skb->end) {
                    unsigned char* tail_ptr = skb_tail_pointer(skb);
                    ptr = (struct xorhdr *)(tail_ptr);
                    printk(KERN_INFO "CBin:%d\n", ptr->in);
                    printk(KERN_INFO "CBout:%d\n", ptr->out);
                }

            } else {
                if (skb_headroom(skb) > sizeof(struct xorhdr)) {
                    struct xorhdr *xorh;
                    xorh = kmalloc(sizeof(struct xorhdr), GFP_ATOMIC);
                    unsigned char *new_data;

                    new_data = skb_tail_pointer(skb);
                    if (skb->tail + sizeof(struct xorhdr) < skb->end) {
                        xorh->in = 6;
                        xorh->out = 5;
                        printk(KERN_INFO "CBin:%d\n", xorh->in);
                        printk(KERN_INFO "CBout:%d\n", xorh->out);
                        skb->tail += sizeof(struct xorhdr);
                        skb->len += sizeof(struct xorhdr);
                        memcpy(new_data, xorh, sizeof(struct xorhdr));
                    }

                    kfree(xorh);

                    // update ip header pointer 
                    iph = ip_hdr(skb);

                    // calculate udp checksum
                    uh = udp_hdr(skb);
                    uh->check = 0;
                    uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ip_payload_len(iph), IPPROTO_UDP, csum_partial(uh, ip_payload_len(iph), skb->csum));
                    skb->ip_summed = CHECKSUM_NONE;

                    // calculate ip checksum 
                    ip_send_check (iph);

                }
            }
            PRINTK("\n****************************\n\n");
        }


    }

    accept:
        return NF_ACCEPT;
}

我做错了什么?

最佳答案

我解决了将 skb->tail 移回原始位置的问题:skb->tail -= sizeof(struct xorhdr);。因此,当我在另一端收到包裹时,我使用我放入的数据,并将 skb->tail 返回到原始位置。

struct xorhdr {
    int in;
    int out;
};

static unsigned int asnfwd_hook(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;
    struct asnfwd_opt *opt;
    __be32 addr = 0;
    struct tcphdr *th;
    struct udphdr *uh;

    /* sanity check */
    if (!skb)
        goto accept;

    /* recover the IPv4 header */
    iph = ip_hdr(skb);
    if (!iph)
        goto accept;

    if (iph->protocol == 17) {
        uh = (struct udphdr *) skb_transport_header(skb);
        if ((unsigned int) ntohs(uh->source) == XOR_PORT && (unsigned int) ntohs(uh->dest) == XOR_PORT) {
            printk("\n****************************\n");
            printk("Hook is %s\n", (in ? "pre-routing" : "local-out"));
            printk("(Ogirinal) From %pI4 to %pI4.\n", &iph->saddr, &iph->daddr);
            printk(KERN_INFO "free:%d", skb_headroom(skb));

            if (in) {
                struct xorhdr *ptr;

                if (skb->tail + sizeof(struct xorhdr) < skb->end) {
                    unsigned char* tail_ptr = skb_tail_pointer(skb);
                    ptr = (struct xorhdr *)(tail_ptr);
                    printk(KERN_INFO "CBin:%d\n", ptr->in);
                    printk(KERN_INFO "CBout:%d\n", ptr->out);
                    skb->tail -= sizeof(struct xorhdr);

                    // update ip header pointer 
                    iph = ip_hdr(skb);

                    // calculate udp checksum
                    uh = udp_hdr(skb);
                    uh->check = 0;
                    uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ip_payload_len(iph), IPPROTO_UDP, csum_partial(uh, ip_payload_len(iph), skb->csum));
                    skb->ip_summed = CHECKSUM_NONE;

                    // calculate ip checksum 
                    ip_send_check (iph);
                }

            } else {
                if (skb_headroom(skb) > sizeof(struct xorhdr)) {
                    struct xorhdr *xorh;
                    xorh = kmalloc(sizeof(struct xorhdr), GFP_ATOMIC);
                    unsigned char *new_data;

                    new_data = skb_tail_pointer(skb);
                    if (skb->tail + sizeof(struct xorhdr) < skb->end) {
                        xorh->in = 6;
                        xorh->out = 5;
                        printk(KERN_INFO "CBin:%d\n", xorh->in);
                        printk(KERN_INFO "CBout:%d\n", xorh->out);
                        skb->tail += sizeof(struct xorhdr);
                        skb->len += sizeof(struct xorhdr);
                        memcpy(new_data, xorh, sizeof(struct xorhdr));
                    }

                    kfree(xorh);

                    // update ip header pointer 
                    iph = ip_hdr(skb);

                    // calculate udp checksum
                    uh = udp_hdr(skb);
                    uh->check = 0;
                    uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ip_payload_len(iph), IPPROTO_UDP, csum_partial(uh, ip_payload_len(iph), skb->csum));
                    skb->ip_summed = CHECKSUM_NONE;

                    // calculate ip checksum 
                    ip_send_check (iph);

                }
            }
            PRINTK("\n****************************\n\n");
        }


    }

    accept:
        return NF_ACCEPT;
}

关于c - 将数据添加到特定协议(protocol)的数据包中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36323475/

相关文章:

c - USB 的简单内核模块

C中检查字符串是否包含子字符串

c - sk_buff 复制 & sk_buff 克隆

c++ - 64 位 DLL 中的 CreateThread 不起作用

networking - 如何延长 igraph 网络图中的边 (layout=fruchterman.reingold)?

networking - 用于对声音进行分类的时间 CNN : cur_target assertion

java - Java 中的链接状态通知

linux - 修改Linux Kernel中Sysfs的/sys/devices/system/memory/目录

硬币-文件读取方法中的SPOJ TLE

C 代码、scanf 和 getchar