LINUX.ORG.RU

Переслать полученный пакет

 , ,


0

1

Привет.
Появилась задача переслать полученный пакет обратно в сеть. Из-за того, что это нужно делать максимально быстро(важно быстродействие), было принято решение делать это через модуль ядра.
Для этого пишу функцию, которая вызывается при получении каждого пакета и регистрирую ее в различные обработчики.
В качестве примера брал код отсюда: 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);
}

Проблемы две: постоянно ловлю панику ядра и мои пакеты не уходят в сеть(мониторю вайршарками на обеих машинах).

Deleted

Ответ на: комментарий от anonymous

Да, я наркоман и ночью меня переклинило.

Deleted ()
Ответ на: комментарий от thesis

Ковыряться в сорцах ипстолов хочется в последнюю очередь, но, если ничего не останется, видимо, придется.

Deleted ()

У меня вопрос, ты читал про ядро, сетевой стек, программирование под это дело? или взял все с потолка?

Boy_from_Jungle ★★★★ ()
Ответ на: комментарий от Deleted

блин, в заднице тебе не лень ковыряться? Что твой get_net_dev() делает вообще? Руки из жопы вынь для начала. И голову тоже.

anonymous ()
Ответ на: комментарий от Boy_from_Jungle

Читал и представляю, что происходит в этом коде. Хотя, не спорю, мой опыт на нулевой отметке.

Deleted ()
Ответ на: комментарий от anonymous

get_net_dev не делает ничего, рудимент, оставшийся от прощлых неудачных попыток послать данные через raw-сокет.

Deleted ()
Ответ на: комментарий от Deleted

так -j TEE и как раз отдает пакет обратно в сеть. Очень быстро. Зачем ковырять исходники, если надо просто прописать правило?

greek_31 ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.