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

C 无法通过dev_queue_xmit()发送数据包,c,linux-kernel,ip,netfilter,C,Linux Kernel,Ip,Netfilter,我想在NF_IP_LOCAL_OUT钩子中捕获数据包,并稍微修改它们。之后,我使用dev\u queue\u 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

我想在NF_IP_LOCAL_OUT钩子中捕获数据包,并稍微修改它们。之后,我使用
dev\u queue\u 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);
静态结构nf\u hook\u ops modify\u ops;
静态无符号整数修改(无符号整数hooknum、结构sk_buff*skb、常量结构net_设备*in、常量结构net_设备*out、int(*okfn)(结构sk_buff*))
{
结构sk_buff*nskb;
结构iphdr*nip_hdr;
未签名的int nip_hdr_off;
结构icmphdr*icmph=NULL;
int-ret=0;
结构net*net=NULL;
nskb=skb_拷贝(skb,GFP_原子);
if(nskb==NULL)
{
printk(“%s\n”,“skb_拷贝返回空”);
返回NF_接受;
}
if(ip_hdr(nskb)->协议!=IPPROTO_ICMP)
{
kfree_skb(nskb);
返回NF_接受;
}
nip_hdr=ip_hdr(nskb);//nip_hdr=nskb->nh.iph;
nip_hdr_off=nip_hdr->ihl daddr=in_aton(“192.168.1.1”);
nip_hdr->检查=0;
nip_hdr->check=ip_fast_csum((无符号字符*)nip_hdr,nip_hdr->ihl);
icmph=icmp_hdr(nskb);
icmph->校验和=0;
icmph->校验和=校验和((无符号短*)icmph,
ntohs(nip_hdr->tot_len)-sizeof(结构iphdr);
nskb->csum=0;
nskb->csum=csum_部分((无符号字符*)(ntcp_hdr+ntcp_hdr_off),
ntohs(nip_hdr->tot_len)-
nip_hdr_off-ntcp_hdr_off,0);
nskb->ip_summated=校验和无;
nskb->pkt\u type=PACKET\u outing;//PACKET\u OTHERHOST;
neth_hdr=(struct ethhdr*)skb_push(nskb,ETH_HLEN);
skb_重置_mac_头(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\u-get\u-by\u-name(&init\u-net,ETH);
如果(nskb->dev==NULL)
{
printk(“%s\n”,“dev_get_by_name返回NULL”);
kfree_skb(nskb);
返回NF_接受;
}
开发保持(nskb->开发);
printk(“%s\n”,“dev_hold ok”);
dev_put(nskb->dev);
ret=dev_queue_xmit(nskb);
printk(“ret:%d\n”,ret);
归还被盗的NFU;
}
静态int uu init init(void)
{
int-ret=0;
modify_ops.hook=修改;
修改_ops.hooknum=3;//NF\u IP\u LOCAL\u OUT;
修改_ops.pf=pf_INET;
修改操作优先级=NF\u IP\u PRI\u优先;
ret=nf\U寄存器\U挂钩(和修改操作);
如果(ret<0)
{
printk(“%s\n”,“无法修改skb挂钩!”);
返回ret;
}
printk(“%s\n”、“insmod修改skb模块”);
返回0;
}
静态无效\uuu退出fini(无效)
{
取消注册挂机(和修改操作);
printk(“%s\n”,“删除修改skb模块”);
}
模块_init(init);
模块_出口(fini);

数据包中未设置ICMP校验和。已计算校验和,但将其放入
nskb->csum
,这在本文中没有意义

以下是我认为的问题:

调用
NF\u IP\u LOCAL\u OUT
时,数据包的MAC头尚未设置。
然而,dev_queue_xmit希望MAC头就位

设置MAC报头(可能涉及发送ARP数据包)是在
ip_finish_output
中,挂接之后,调用
dev_queue_xmit
之前完成的


您不应该调用
dev\u queue\u xmit
。如果您不能简单地返回
NF\u ACCEPT
,则需要重新注入数据包(
NF\u reinject
)。

谢谢您的评论。实际上,在代码中,我设置了MAC头。我认为通过dev_queue_xmit交付数据包应该是可以的。你确实可以。我仍然认为,如果您将数据包注入到相同的位置(即
nf_reinject
),事情会更顺利。不管怎样,ICMP校验和呢
nskb->csum
没有设置它。是的,您是正确的。我错误地注释掉了ICMP校验和和和SKB cheksum。看来ICMP数据包现在可以通过了。我更正了上面的代码。谢谢。我在答案中加上了这个解释。你能告诉我们这些包是怎么没有被发送出去的吗?例如,您是否使用tcpDump或wireshark进行了检查?还是内核崩溃了?或者到底是什么?