3

PRE_ROUTING フックで大きなパケットを小さなパケットに分割する必要があります。パケットを小さなものに分割する、skb を作成する、ip および udp ヘッダーを設定するなどの必要な手順を実行しました。しかし、パケットをルーティングする方法がわかりません。パケットにデータを追加できるようになりました (これは、以前の質問: How to append data on a packet from kernel space? で確認できます)。しかし今、分割されたパケットのルーティングに行き詰まっています。前もって感謝します。

以下にコードを示します(これまでのところ、私は書くことができます)。モジュールがサーバー マシン上で実行されているとします。サーバーはポート 6000 で実行されます。クライアントはメッセージ「ThisIsUsedForTesting」を送信します。コードによると、サーバーは「ThisI」(より小さいパケット) を取得する必要があります。私は今、2 番目のパケットには関係ありません。パケットサイズを簡単に壊すことができます。しかし、今では 2 つ以上のパケットが存在する可能性があります。

このモジュールを実行すると、サーバーは「ThisI」というメッセージを受け取ります。しかし、それをエコーバックすると、パケットは箱から出ません。PRE_ROUTING 用のモジュールを作成すると、マシンはすぐに oops を実行するはずですが、サーバー プロセスがメッセージを取得すると、マシンは oops を実行します。これらのシナリオがわかりません。どんな助け/提案も大歓迎です。最初の分割されたパケットを管理できれば、残りは自動的に処理できると思うので、それらのコードはここでは示しません。

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/skbuff.h>
    #include <linux/netfilter.h>
    #include <linux/netdevice.h>
    #include <linux/ip.h>
    #include <linux/udp.h>
    #include <linux/mm.h>
    #include <linux/err.h>
    #include <linux/crypto.h>
    #include <linux/init.h>
    #include <linux/crypto.h>
    #include <linux/scatterlist.h>
    #include <net/ip.h>
    #include <net/udp.h>
    #include <net/route.h>
    #include <linux/netfilter_ipv4.h>

    #define IP_HDR_LEN 20
    #define UDP_HDR_LEN 8
    #define TOT_HDR_LEN 28

    static unsigned int pkt_split_begin(unsigned int hooknum,
                            struct sk_buff *skb,
                            const struct net_device *in,    
                            const struct net_device *out,
                            int (*okfn)(struct sk_buff *));

    static void skb_print_info(const struct sk_buff *skb);
    static void ip_print_info(struct iphdr *iph);
    static void udp_print_info(struct udphdr *udph);
    static void data_print_info(unsigned char *data, int len);

    static struct nf_hook_ops pkt_split_ops __read_mostly = {
        .pf = NFPROTO_IPV4,
        .priority = 1,
        .hooknum = NF_INET_PRE_ROUTING,
        .hook = pkt_split_begin,
    }; 

static int __init pkt_split_init(void)
{
    printk(KERN_ALERT "\npkt_split module started ...");
    return nf_register_hook(&pkt_split_ops);
}

static void __exit pkt_split_exit(void)
{
    nf_unregister_hook(&pkt_split_ops);
    printk(KERN_ALERT "pkt_split module stopped ...");
}

static unsigned int pkt_split_begin (unsigned int hooknum,
                        struct sk_buff *skb,
                        const struct net_device *in,
                        const struct net_device *out,
                        int (*okfn)(struct sk_buff *))
{
    struct iphdr *iph;
    struct udphdr *udph;
    unsigned char *data;

    unsigned int data_len;

    unsigned int i;

    unsigned char *temp;
    unsigned char *temp1, *temp2;
    unsigned char *ptr;

    __u16 dst_port, src_port;

    if (skb) {
        iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);

        if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) {
            udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
            src_port = ntohs (udph->source);
            dst_port = ntohs (udph->dest);

            if (dst_port == 6000) {
                printk(KERN_ALERT "\nUDP packet goes in");
                data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
                data_len = skb->len - TOT_HDR_LEN;

                temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                memcpy(temp, data, data_len);

                temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);

                unsigned int len1, len2;

                len1 = 5;
                len2 = data_len - len1;

                memcpy(temp1, temp, len1);
                temp1[len1] = '\0';
                printk(KERN_ALERT "temp1: %s", temp1);

                ptr = temp + len1;
                memcpy(temp2, ptr, len2);
                printk(KERN_ALERT "temp2: %s", temp2);

                struct sk_buff *skb1, *skb2;
                struct iphdr *iph1, *iph2;
                struct udphdr *udph1, *udph2;
                unsigned char *data1, *data2;
                int data_len1, data_len2;

                skb1 = skb_copy(skb, GFP_ATOMIC);
                skb2 = skb_copy(skb, GFP_ATOMIC);

                iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
                udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
                data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
                data_len1 = skb1->len - len2 - TOT_HDR_LEN + 1;

                memset(data1, 0, data_len);
                memcpy(data1, temp1, data_len1);
                skb1->len = data_len1 + TOT_HDR_LEN;
                iph1->tot_len = htons(data_len1 + TOT_HDR_LEN);
                udph1->len = htons(data_len1 + UDP_HDR_LEN);
                skb1->tail = skb1->tail - data_len2 + 1;


                /* Calculation of IP header checksum */
                iph1->check = 0;
                ip_send_check (iph1);

                /* Calculation of UDP checksum */
                udph1->check = 0;
                int offset = skb_transport_offset(skb1);
                int len = skb1->len - offset;
                udph1->check = ~csum_tcpudp_magic((iph1->saddr), (iph1->daddr), len, IPPROTO_UDP, 0);

                struct sk_buff *tempskb;

                tempskb = skb_copy(skb, GFP_ATOMIC);

                *tempskb = *skb;
                *skb = *skb1;
                *skb1 = *tempskb;

                (*okfn)(skb);

                skb_print_info(skb1);
                ip_print_info(iph1);
                udp_print_info(udph1);
                data_print_info(data1, data_len1);

                kfree_skb(skb1);

            }
        }
    }
    return NF_DROP;
}

static void skb_print_info (const struct sk_buff *skb)
{
    printk(KERN_ALERT "\nPrinting SKB info: ");

    printk(KERN_ALERT "len: %d", skb->len);
    printk(KERN_ALERT "tail: %d", skb->tail);
    printk(KERN_ALERT "end: %d", skb->end);
    printk(KERN_ALERT "head: %x", skb->head);
    printk(KERN_ALERT "data: %x", skb->data);

    printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
    printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
    printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
    printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));

}

void ip_print_info (struct iphdr *iph)
{
    printk(KERN_ALERT "\nPrinting IP header info:");

    printk(KERN_ALERT "ihl = %d", iph->ihl);
    printk(KERN_ALERT "version = %d", iph->version);
    printk(KERN_ALERT "tos = %d", iph->tos);
    printk(KERN_ALERT "tot_len = %d", ntohs(iph->tot_len));
    printk(KERN_ALERT "id = %d", ntohs(iph->id));
    printk(KERN_ALERT "frag_off = %d", ntohs(iph->frag_off));
    printk(KERN_ALERT "ttl = %d", iph->ttl);
    printk(KERN_ALERT "protocol = %d", iph->protocol);
    printk(KERN_ALERT "check = %x", ntohs(iph->check));
    printk(KERN_ALERT "saddr = %x", ntohl(iph->saddr));
    printk(KERN_ALERT "daddr = %x", ntohl(iph->daddr));
}

void udp_print_info (struct udphdr *udph)
{
    printk(KERN_ALERT "\nPrinting UDP header info: ");

    printk(KERN_ALERT "source = %d", ntohs(udph->source));
    printk(KERN_ALERT "dest = %d", ntohs(udph->dest));
    printk(KERN_ALERT "len = %d", ntohs(udph->len));
    printk(KERN_ALERT "check = %x", ntohs(udph->check));
}


void data_print_info (unsigned char *data, int len)
{
    printk(KERN_ALERT "\nPrinting data info: ");

    printk(KERN_ALERT "Data: %s", data);
    printk(KERN_ALERT "data_len: %d", len);
}

module_init(pkt_split_init);
module_exit(pkt_split_exit);

MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi@gmail.com>");
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space");
MODULE_LICENSE("GPL");
4

1 に答える 1

5

今回は解決策を見つけました。また、前のケース (http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space) のような単純なケースです。コードを提示しています。しかし、私が説明しなければならないことがあります。

okfn

のように呼び出す必要があります

okfn(skb);

そして、skb自体を解放します。そして、質問での私の問題は、skb を二重に解放することでした。次のコードを見ると、それを行うために何が必要かがわかります。コードはテスト目的でのみ使用されます。最初の 5 バイト (および '\0' を加えたもの) は新しいパケットの作成に使用され、残りのデータは 2 番目のパケットの作成に使用されます。では、どうぞ。skb 情報、ip ヘッダー情報などを印刷するために必要なヘルパー関数が便宜上提供されています (何が起こっているのかを理解するために使用しました)。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/route.h>
#include <linux/netfilter_ipv4.h>

#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28

static unsigned int pkt_split_begin(unsigned int hooknum,
                        struct sk_buff *skb,
                        const struct net_device *in,
                        const struct net_device *out,
                        int (*okfn)(struct sk_buff *));

static void skb_print_info(const struct sk_buff *skb);
static void ip_print_info(struct iphdr *iph);
static void udp_print_info(struct udphdr *udph);
static void data_print_info(unsigned char *data, int len);

static struct nf_hook_ops pkt_split_ops __read_mostly = {
    .pf = NFPROTO_IPV4,
    .priority = 1,
    .hooknum = NF_INET_PRE_ROUTING,
    .hook = pkt_split_begin,
};

static int __init pkt_split_init(void)
{
    printk(KERN_ALERT "\npkt_split module started ...");
    return nf_register_hook(&pkt_split_ops);
}

static void __exit pkt_split_exit(void)
{
    nf_unregister_hook(&pkt_split_ops);
    printk(KERN_ALERT "pkt_split module stopped ...");
}

static unsigned int pkt_split_begin (unsigned int hooknum,
                        struct sk_buff *skb,
                        const struct net_device *in,
                        const struct net_device *out,
                        int (*okfn)(struct sk_buff *))
{
    struct iphdr *iph;
    struct udphdr *udph;
    unsigned char *data;

    unsigned int data_len;

    unsigned int i;

    unsigned char *temp;
    unsigned char *temp1, *temp2;
    unsigned char *ptr;

    __u16 dst_port, src_port;

    if (skb) {
        iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL);

        if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) {
            udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL);
            src_port = ntohs (udph->source);
            dst_port = ntohs (udph->dest);

            if (dst_port == 6000) {
                printk(KERN_ALERT "\nUDP packet goes in");
                data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
                data_len = skb->len - TOT_HDR_LEN;

                temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                memcpy(temp, data, data_len);

                temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);

                unsigned int len1, len2;

                len1 = 5;
                len2 = data_len - len1;

                memcpy(temp1, temp, len1);
                temp1[len1] = '\0';
                printk(KERN_ALERT "temp1: %s", temp1);

                ptr = temp + len1;
                memcpy(temp2, ptr, len2);
                printk(KERN_ALERT "temp2: %s", temp2);

                struct sk_buff *skb1, *skb2;
                struct iphdr *iph1, *iph2;
                struct udphdr *udph1, *udph2;
                unsigned char *data1, *data2;
                int data_len1, data_len2;

                skb1 = skb_copy(skb, GFP_ATOMIC);
                skb2 = skb_copy(skb, GFP_ATOMIC);

                iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
                udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
                data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
                data_len1 = skb1->len - len2 -TOT_HDR_LEN + 1;

                memset(data1, 0, data_len);
                memcpy(data1, temp1, data_len1);
                skb1->len = data_len1 + TOT_HDR_LEN;
                iph1->tot_len = htons(data_len1 + TOT_HDR_LEN);
                udph1->len = htons(data_len1 + UDP_HDR_LEN);
                skb1->tail = skb1->tail - data_len2 + 1;

                /* Calculation of IP header checksum */
                iph1->check = 0;
                ip_send_check (iph1);

                /* Calculation of UDP checksum */
                udph1->check = 0;
                int offset = skb_transport_offset(skb1);
                int len = skb1->len - offset;
                udph1->check = ~csum_tcpudp_magic((iph1->saddr), (iph1->daddr), len, IPPROTO_UDP, 0);

                /* Dealing with the second packet */
                iph2 = (struct iphdr *) skb_header_pointer(skb2, 0, 0, NULL);
                udph2 = (struct udphdr *) skb_header_pointer(skb2, IP_HDR_LEN, 0, NULL);
                data2 = (unsigned char *) skb_header_pointer(skb2, TOT_HDR_LEN, 0, NULL);
                data_len2 = skb2->len - len1 - TOT_HDR_LEN;

                memset(data2, 0, data_len);
                memcpy(data2, temp2, data_len2);
                skb2->len = data_len2 + TOT_HDR_LEN;
                iph2->tot_len = htons(data_len2 + TOT_HDR_LEN);
                udph2->len = htons(data_len2 + UDP_HDR_LEN);
                skb2->tail = skb2->tail - data_len1;

                /* Calculation of IP header checksum */
                iph2->check = 0;
                ip_send_check (iph2);

                /* Calculation of UDP checksum */
                udph2->check = 0;
                offset = skb_transport_offset(skb1);
                len = skb2->len - offset;
                udph2->check = ~csum_tcpudp_magic((iph2->saddr), (iph2->daddr), len, IPPROTO_UDP, 0);

                okfn(skb1);
                okfn(skb2);
            }
        }
    }
    return NF_DROP;
}

static void skb_print_info (const struct sk_buff *skb)
{
    printk(KERN_ALERT "\nPrinting SKB info: ");

    printk(KERN_ALERT "len: %d", skb->len);
    printk(KERN_ALERT "tail: %d", skb->tail);
    printk(KERN_ALERT "end: %d", skb->end);
    printk(KERN_ALERT "head: %x", skb->head);
    printk(KERN_ALERT "data: %x", skb->data);

    printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
    printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
    printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
    printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));

}

void ip_print_info (struct iphdr *iph)
{
    printk(KERN_ALERT "\nPrinting IP header info:");

    printk(KERN_ALERT "ihl = %d", iph->ihl);
    printk(KERN_ALERT "version = %d", iph->version);
    printk(KERN_ALERT "tos = %d", iph->tos);
    printk(KERN_ALERT "tot_len = %d", ntohs(iph->tot_len));
    printk(KERN_ALERT "id = %d", ntohs(iph->id));
    printk(KERN_ALERT "frag_off = %d", ntohs(iph->frag_off));
    printk(KERN_ALERT "ttl = %d", iph->ttl);
    printk(KERN_ALERT "protocol = %d", iph->protocol);
    printk(KERN_ALERT "check = %x", ntohs(iph->check));
    printk(KERN_ALERT "saddr = %x", ntohl(iph->saddr));
    printk(KERN_ALERT "daddr = %x", ntohl(iph->daddr));
}

void udp_print_info (struct udphdr *udph)
{
    printk(KERN_ALERT "\nPrinting UDP header info: ");

    printk(KERN_ALERT "source = %d", ntohs(udph->source));
    printk(KERN_ALERT "dest = %d", ntohs(udph->dest));
    printk(KERN_ALERT "len = %d", ntohs(udph->len));
    printk(KERN_ALERT "check = %x", ntohs(udph->check));
}


void data_print_info (unsigned char *data, int len)
{
    printk(KERN_ALERT "\nPrinting data info: ");

    printk(KERN_ALERT "Data: %s", data);
    printk(KERN_ALERT "data_len: %d", len);
}

module_init(pkt_split_init);
module_exit(pkt_split_exit);

MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi@gmail.com>");
MODULE_DESCRIPTION("Inward Packet Splitting in kernel space");
MODULE_LICENSE("GPL");

だから...私はカーネル空間プログラミングが初めてなので、改善のための提案は大歓迎です。

于 2012-10-25T14:11:19.030 に答える