我想在 Net Filter Hook 处复制数据包(并将其发送到我创建的队列)。 skb_copy 对我有用吗?我还必须在数据包之前添加 seq no,skb_reserve 会这样做吗? 我写了下面的代码来抓包
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
if (strcmp(in->name, drop_if) == 0) {
printk("Dropped packet on %s...\n", drop_if);
return NF_DROP;
} else {
return NF_ACCEPT;
}
}
/* Initialisation routine */
int init_module()
{
/* Fill in our hook structure */
nfho.hook = hook_func; /* Handler function */
nfho.hooknum = NF_IP_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
return 0;
}
最佳答案
我同意 Rachit Jain 的观点,除非您有正当理由在内核空间中执行此操作,否则我建议您使用 libpcap 在用户空间中执行此操作。
无论如何,如果你只是想复制数据包然后修改一些数据,我建议你分配一个有足够空间的新skb来复制你收到的skb中已有的数据+足够的空间来添加一个头。
这是我曾经使用过的代码,它不会从已经存在的 skb
中进行任何复制,但它可能对您有用。我在这里制作了一种特殊的 ICMP 回显消息
int sendICMPEcho(unsigned char *msg, unsigned int length,
__be32 source, __be32 dest)
{
struct ethhdr *eth;
struct iphdr *iph;
struct icmphdr *icmph;
struct sk_buff *newPacket;
unsigned char *data;
unsigned int skbSize = length + sizeof(struct icmphdr)
+ sizeof(struct iphdr)
+ sizeof(struct ethhdr);
/* Allocate the skb */
newPacket = alloc_skb(skbSize, GFP_ATOMIC);
if(newPacket == NULL)
return SEND_FAIL_MEMORY;
/* Reserve the headers area */
skb_reserve(newPacket, sizeof(struct icmphdr)
+ sizeof(struct iphdr)
+ sizeof(struct ethhdr));
/* Extend the data area from 0 to the message length */
data = skb_put(newPacket, length);
/* Copy the data from the message buffer to the newPacket */
memcpy(data, msg, length);
/************** ICMP HEADER***************/
/* skb_push - pushing the icmp header in the packet data */
icmph = (struct icmphdr *) skb_push(newPacket,
sizeof(struct icmphdr));
/*set ICMP header here */
icmph->type = ICMP_ECHO;
icmph->code = 100; /* Our magic number */
icmph->un.echo.id = 0;
icmph->un.echo.sequence = htons(sendCounter);
icmph->checksum= 0;
icmph->checksum = in_cksum((unsigned short *)icmph,
sizeof(struct icmphdr) + length);
/************** END ICMP HEADER**************/
/************** IP HEADER ***************/
iph = (struct iphdr *) skb_push(newPacket,
sizeof(struct iphdr));
/* set IP header here */
iph->ihl = 5;/* 5 * 32(bits) */
iph->version = 4;
iph->tos = 255; /* Just a magic number - remove it */
iph->tot_len = htons( sizeof(struct iphdr)
+ sizeof(struct icmphdr)
+ length);
iph->id = 0;
iph->frag_off = 0; /* No fragementation */
iph->ttl = 65;
iph->protocol = IPPROTO_ICMP;
iph->saddr = source;
iph->daddr = dest;
iph->check = 0;
iph->check = in_cksum((unsigned short *)iph, sizeof(struct iphdr));
/************** END IP HEADER ***************/
/*WARNING: THE CODE BELOW SHOULD BE REPLACED BY SOMETHING MORE ROBUST
THAT USES THE KERNEL ROUTING!
AND USES IP_LOCAL_OUT INSTEAD OF WHAT WE ARE DOING */
/* Set up the net-device for the new packet */
/* In my code, there was a function findDeviceByIp that does the routing and return which net_device to use for transmission*/
newPacket->dev = findDeviceByIP(source);
if(newPacket->dev == NULL)
{
kfree_skb(newPacket);
return SEND_DEV_FAIL;
}
/************** ETH HEADER ***************/
eth = (struct ethhdr *) skb_push(newPacket, sizeof(struct ethhdr));
if(strcmp(newPacket->dev->name, "wlan0") == 0)
memcpy(eth->h_dest, wifiMAC, 6);
else if(strcmp(newPacket->dev->name, "eth0") == 0)
memcpy(eth->h_dest, etherMAC, 6);
else
{
kfree_skb(newPacket);
return SEND_FAIL_SEND;
}
memcpy(eth->h_source, newPacket->dev->dev_addr, 6);
eth->h_proto = htons(ETH_P_IP);
/************** END ETH HEADER ***************/
dev_queue_xmit(newPacket);/* Transmite the packet */
/* END OF THE WARNING AREA */
++sendCounter;
return SEND_SUCCESS;
}
关于linux - 如何制作数据包的副本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20833852/