Reputation: 93
I want to make a copy of the packet (and send it to queue that is made by me) at the Net Filter hook. Will skb_copy work for me? i also have to add the seq no before the packet,skb_reserve will do that? I have written the following code to capture packet
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;
}
Upvotes: 0
Views: 2852
Reputation: 409
There are many helper functions provided by linux kernel to work on skb's. it depends on the usecase which one you want to use.
skb_clone ==>copies the skbuff header and increments the reference counter for data buffer. If you are only interested in modifying the skbuff header then you can use skb_clone
skb_copy ==> copies skbuff header, data buffer as well as fragments. Use when you are interested in modifying the data in main buffer as well as in fragments buffer
pskb_copy ==> copies skbuff header + only the data buffer but not the fragments, thus if you want to modify skb except fragment buffer then you can use this one. which takes headroom also as arguement.
Better read the helper function provided by linux kernel(net/core/skbuff.c) to do the skb operations efficiently and to avoid any pitfalls.
Upvotes: 0
Reputation: 5533
I do agree with Rachit Jain, unless you have a valid reason to do this in Kernel space, I do suggest you use libpcap to do it in user-space.
Anyhow, if you just wanna copy the packet and then amend some data, I suggest you allocate a new skb with enough space to copy the data you already have in the skb you received + enough space to add a header.
Here's a code that I once used, it doesn't do any copying from an already existing skb
but it can be useful to you. I am crafting a special kind of ICMP echo message here
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;
}
Upvotes: 1