I have a kernel module that captures outgoing Internet traffic(Netfilter hook: LOCAL_OUT) At this hook, there\'s still no Ethernet header.
I built the Ethernet header an
unsigned int snoop_hook1( unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int(*okfn)( struct sk_buff * ) )
{
int offset, len,tcplen;
struct ethhdr *ethh;
struct iphdr *iph;
struct tcphdr *tcph;
uint16_t t;
bool flag = false;
struct sk_buff *nskb;
struct net_device *eth1_dev , *lo_dev;
if (!skb) return NF_ACCEPT;
iph = ip_hdr(skb);
if (!iph) return NF_ACCEPT;
tcph = tcp_hdr(skb);
/* skip lo packets */
if (iph->saddr == iph->daddr) return NF_ACCEPT;
if (tcph->dest == htons(80))
flag=true;
// add similar conditions for true flags
if(flag != true)
return NF_ACCEPT;
/* print packet information */
printk(KERN_INFO "HELLO !!!\n");
printk(KERN_INFO "HOOK=NF_INET_LOCAL_OUT");
printk(KERN_INFO "INDEV %s OUTDEV %s",in->name, out->name);
printk(KERN_INFO "sk_buff::dev %s",skb->dev->name);
//printk(KERN_INFO "MAC ADDRESSES as in eth header %pM->%pM", &(ethh->h_source), &(ethh->h_dest));
printk( KERN_INFO " %pI4->%pI4\n", &(iph->saddr), &(iph->daddr));
printk(KERN_INFO "TCP SRC:%d, TCP DST:%d",ntohs(tcph->source),ntohs(tcph->dest));
// correct the IP checksum
printk(KERN_INFO "IP checksum =%d",iph->check);
iph->check = 0;
ip_send_check (iph);
printk(KERN_INFO "IP checksum new =%d",iph->check);
//correct the TCP checksum
printk(KERN_INFO "TCP checksum =%d",tcph->check);
offset = skb_transport_offset(skb);
len = skb->len - offset;
printk(KERN_INFO "skb->len=%d",skb->len);
printk(KERN_INFO "offset=%d",offset);
printk(KERN_INFO "len=%d",len);
tcph->check = 0;
if(skb->len > 60){
tcph->check = csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, csum_partial((unsigned char *)tcph,len,0));
printk(KERN_INFO "TCP checksum new=%d",tcph->check);
}
else{
tcph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, 0);
printk(KERN_INFO "TCP checksum new*=%d",tcph->check);
}
printk(KERN_INFO "************************************************************");
//send to dev
eth1_dev = dev_get_by_name(&init_net,"eth1");
lo_dev = dev_get_by_name(&init_net,"lo");
skb->dev = eth1_dev;
ethh = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb->protocol = ethh->h_proto = htons(ETH_P_IP);
memcpy (ethh->h_source,eth1_dev->dev_addr , ETH_ALEN);
memcpy (ethh->h_dest, d_mac, ETH_ALEN);
dev_queue_xmit(skb);
return NF_STOLEN;
}
This is an old question(and answer ) .I needed to do something exactly similar and I ended up with this code. Thought of showing it for helping others. It works for me at least , I am sending the same skb here . d_mac is the mac of the gateway or another mac in the lan . It can be obtained from incoming packets or from arp.