我想捕获NF_IP_LOCAL_OUT挂钩中的数据包,并稍微修改它们。之后,我使用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);
答案 0 :(得分:1)
未在数据包中设置ICMP校验和。计算了校验和,但是放入了nskb->csum
,这在这种情况下毫无意义。
以下是我遇到的问题:
在调用NF_IP_LOCAL_OUT
时,数据包的MAC标头尚未设置
但是,dev_queue_xmit
期望MAC标头到位。
设置MAC头(可能涉及发送ARP数据包)在ip_finish_output
之后,在挂钩之后,在调用dev_queue_xmit
之前完成。
你不应该致电dev_queue_xmit
。如果您不能简单地返回NF_ACCEPT
,则需要重新注入数据包(nf_reinject
)。
答案 1 :(得分:0)
如ugoren所述,dev_queue_xmit
通常在已填充MAC地址的网络堆栈的后期调用。创建新的skb(在您的情况下为skb_copy()
)并希望将其发送出去时,您可以:
像大多数示例代码一样,在调用dev_queue_xmit
之前手动填充MAC地址。
使用其他方式插入新的skb。
以NF_INET_POST_ROUTING
为例。您将要查看是否只返回NF_ACCEPT
,如何插入原始skb。检查这张图片:
NF_INET_POST_ROUTING
的 NF_HOOK应该属于net / ipv4 / ip_output.c块。在NF_NOOK之前和之后,涉及ip_output()
和ip_finish_output()
。进一步检查Linux源代码,您可以看到
一些高层调用ip_output()
并传递skb,然后执行某些操作。
涉及到NF_HOOK,而ip_finish_output()
的函数指针也作为okfn
传递到nf钩子函数中。
在调用或不调用nf钩子函数的情况下,将调用ip_finish_output()
,并将skb传递给。进一步挖掘,skb会进入“ hh_cache”的类别,以进行与上述图像匹配的进一步处理。
结论:ip_finish_output()
是在NF_INET_POST_ROUTING
情况下注入skb的功能。如果要发送新的skb,只需将nskb
传递给函数指针okfn
。对于其他情况,例如“ LOCAL_OUT”,“ PRE_ROUTING”等,相应的函数不是ip_finish_output()
,但我认为正确的函数将始终传递到okfn
中,因此netfilter模块编写器不必担心。 / p>