无法通过 dev_queue_xmit() 发送数据包

标签 c linux-kernel ip netfilter

我想捕获 NF_IP_LOCAL_OUT Hook 中的数据包,并对其进行一些修改。之后,我使用 dev_queue_xmit() 发送数据包。不幸的是,虽然函数返回0,但数据包无法成功发送。请问如何解决这个问题?谢谢!

static struct nf_hook_ops modify_ops;

static unsigned int modify(unsigned int hooknum, struct sk_buff * skb, const struct net_device * in, const struct net_device * out, int (*okfn)(struct sk_buff *))
{

        struct sk_buff* nskb;
        struct iphdr* nip_hdr;
        unsigned int   nip_hdr_off;
        struct icmphdr *icmph = NULL;
        int ret = 0;
        struct net *net = NULL;

        nskb = skb_copy(skb, GFP_ATOMIC);
        if(nskb == NULL)
        {
                 printk("%s\n", "skb_copy return NULL");
                 return NF_ACCEPT;
        }


        if( ip_hdr(nskb)->protocol != IPPROTO_ICMP)
        {
                kfree_skb(nskb);
                return NF_ACCEPT;
        }

        nip_hdr = ip_hdr(nskb);   //nip_hdr = nskb->nh.iph;
        nip_hdr_off = nip_hdr->ihl << 2;

        nip_hdr->daddr = in_aton("192.168.1.1");
        nip_hdr->check = 0;
        nip_hdr->check = ip_fast_csum((unsigned char *)nip_hdr, nip_hdr->ihl);
        icmph = icmp_hdr(nskb);
        icmph->checksum = 0;
        icmph->checksum = in_cksum((unsigned short *)icmph,
                        ntohs(nip_hdr->tot_len) - sizeof(struct iphdr));

        nskb->csum = 0;
        nskb->csum = csum_partial((unsigned char *)(ntcp_hdr + ntcp_hdr_off),
                                          ntohs(nip_hdr->tot_len) -
        nip_hdr_off - ntcp_hdr_off, 0);
        nskb->ip_summed = CHECKSUM_NONE;
        nskb->pkt_type  = PACKET_OUTGOING; //PACKET_OTHERHOST;

        neth_hdr = (struct ethhdr *) skb_push(nskb, ETH_HLEN);
        skb_reset_mac_header(nskb);
        nskb->protocol = neth_hdr->h_proto = htons(ETH_P_IP);
        memcpy (neth_hdr->h_dest, DMAC, ETH_ALEN);
        memcpy (neth_hdr->h_source, SMAC, ETH_ALEN);
        nskb->dev = dev_get_by_name(&init_net,ETH);
        if(nskb->dev==NULL)
        {
            printk("%s\n", "dev_get_by_name return NULL");
            kfree_skb(nskb);
            return NF_ACCEPT;
        }

        dev_hold(nskb->dev);
        printk("%s\n", "dev_hold ok");
        dev_put(nskb->dev);

        ret = dev_queue_xmit(nskb);
        printk("ret:%d\n", ret);
        return NF_STOLEN;

}


static int __init init(void)
{
  int  ret = 0;
  modify_ops.hook = modify;
  modify_ops.hooknum = 3; //NF_IP_LOCAL_OUT;
  modify_ops.pf = PF_INET;
  modify_ops.priority = NF_IP_PRI_FIRST;

  ret = nf_register_hook(&modify_ops);
  if (ret < 0)
   {
     printk("%s\n", "can't modify skb hook!");
     return ret;
   }

    printk("%s\n", "insmod modify skb module");
    return 0;
}

static void __exit fini(void)
{
    nf_unregister_hook(&modify_ops);
    printk("%s\n", "remove modify skb module.");
}

module_init(init);
module_exit(fini);

最佳答案

数据包中未设置 ICMP 校验和。计算了校验和,但放入 nskb->csum ,在这种情况下毫无意义。

以下是我认为的问题:

当时NF_IP_LOCAL_OUT被调用时,数据包的 MAC header 尚未设置。
dev_queue_xmit但是,期望 MAC header 就位。

设置 MAC header (可能涉及发送 ARP 数据包)在 ip_finish_output 中完成。 ,在钩子(Hook)之后,在调用 dev_queue_xmit 之前.

您不应该调用 dev_queue_xmit 。如果您不能简单地返回 NF_ACCEPT ,您需要重新注入(inject)数据包( nf_reinject )。

关于无法通过 dev_queue_xmit() 发送数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15934513/

相关文章:

c - Linux C代码如何找到conf文件(一般在/etc)

c - 如何在不为函数指针使用 typedef 的情况下声明函数指针数组?

android - 为 Android 构建 Vanilla 内核时出错

c - 在Linux 2.4中,最小的 child 列表是循环的吗?

windows - 即使我们更改网络,如何使 vm 内的服务器具有相同的 ip 地址

c - 为什么 `gmtime` 需要一个指针?

android - 与 neon 内在函数中的 float 比较

linux - 内核-网络, "private"结构的作用

c# - 如何正确使用BindIPEndPointDelegate?

azure - 如何获取运行Kubernet服务的VM的外部IP