Привет.
Появилась задача переслать полученный пакет обратно в сеть. Из-за того, что это нужно делать максимально быстро(важно быстродействие), было принято решение делать это через модуль ядра.
Для этого пишу функцию, которая вызывается при получении каждого пакета и регистрирую ее в различные обработчики.
В качестве примера брал код отсюда: http://stackoverflow.com/questions/10107367/kernel-module-to-ethernet-packet-...
А так же писал свою реализацию:
//PROTOTYPES/////////////////////////////////////////////////////////////
void* kmemcpy(void*, const void*, ssize_t len);
unsigned int ip_packets_hook(uint hooknum, struct sk_buff* skb,
const struct net_device* in,
const struct net_device* out,
int (*ofkn)(struct sk_buff*));
void get_net_dev();
//GLOBALS///////////////////////////////////////////////////////////////
static struct nf_hook_ops butcher_netfilter_hook;
struct net_device *dev;
int ifindex = NULL;
static struct socket *s;
int tx_len;
struct sockaddr_ll socket_address;
spinlock_t *mr_lock;
unsigned long flags;
//INIT//////////////////////////////////////////////////////////////////
static int __init init(void)
{
printk(KERN_ALERT "module init");
// structure for NetFilter hook
butcher_netfilter_hook.hook = ip_packets_hook;
butcher_netfilter_hook.owner = THIS_MODULE;
butcher_netfilter_hook.pf = PF_INET;
butcher_netfilter_hook.hooknum = NF_INET_PRE_ROUTING;
butcher_netfilter_hook.priority = NF_IP_PRI_FIRST;
nf_register_hook(&butcher_netfilter_hook);
return 0;
}
//EXIT//////////////////////////////////////////////////////////////////
static void __exit exit(void)
{
nf_unregister_hook(&butcher_netfilter_hook);
printk(KERN_ALERT "module exit");
}
////////////////////////////////////////////////////////////////////////
module_init(init);
module_exit(exit);
////////////////////////////////////////////////////////////////////////
//CORE//////////////////////////////////////////////////////////////////
unsigned int ip_packets_hook(uint hooknum, struct sk_buff* skb,
const struct net_device* in,
const struct net_device* out,
int (*ofkn)(struct sk_buff*))
{
printk(KERN_ALERT "whook");
struct iphdr* ip;
struct tcphdr* tcp;
struct sk_buff *my_skb = 0;
my_skb = kmalloc(sizeof(struct sk_buff), GFP_KERNEL);
if(!my_skb)
{
printk(KERN_ALERT "no malloc");
return NF_DROP;
}
else
{
printk(KERN_ALERT "malloc done");
}
memcpy(my_skb, skb, sizeof(struct sk_buff));
// CHECKS IF It's an IP packet
printk(KERN_ALERT "after kmemcpy %d %d %d %d\n", my_skb->protocol, skb->protocol, my_skb->tail, skb->tail);
if (my_skb->protocol == htons(ETH_P_IP))
{
// get IP-header
printk(KERN_ALERT "ip proto\n");
ip = (struct iphdr*)skb_network_header(my_skb);
if (ip->version == 4 && ip->protocol == IPPROTO_ICMP)
{
printk(KERN_ALERT "icmp proto\n");
unsigned char srcaddr[6];
struct ethhdr *eth = eth_hdr(my_skb);
printk(KERN_ALERT "way before sending");
my_skb->dev = in;
my_skb->pkt_type = PACKET_OTHERHOST;
memcpy(srcaddr, eth->h_source, ETH_ALEN);
memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
memcpy(eth->h_dest, srcaddr, ETH_ALEN);
printk(KERN_ALERT "before sending");
if(dev_queue_xmit(my_skb) == NET_XMIT_SUCCESS)
{
printk(KERN_ALERT "success");
}
else
{
printk(KERN_ALERT "phail");
}
// kfree_skb(skb);
// kfree_skb(my_skb);
dev_queue_xmit(skb);
}
}
return NF_ACCEPT;
}
void* kmemcpy(void* dst, const void* src, ssize_t len)
{
char* pdst = (char*)dst;
char* psrc = (char*)src;
int i;
for(i = 0; i < len; i++)
{
*pdst++ = *psrc++;
}
return dst;
}
void get_net_dev(void)
{
read_lock(&dev_base_lock);
for_each_netdev(&init_net, dev) {
if (!strcmp(dev->name,"eth0")){
ifindex = dev->ifindex;
// printk(KERN_INFO "mtu: %d", ifp->mtu);
break;
}
}
read_unlock(&dev_base_lock);
}
Проблемы две: постоянно ловлю панику ядра и мои пакеты не уходят в сеть(мониторю вайршарками на обеих машинах).