How to route the splitted packets using netfilter hooks in kernel space

后端 未结 1 864
鱼传尺愫
鱼传尺愫 2021-01-03 10:21

I have to split large packets into smaller ones in PRE_ROUTING hook. I have done the necessary steps for splitting a packet into smaller ones, creating skb, setting ip and u

相关标签:
1条回答
  • 2021-01-03 10:56

    This time I found the solution. It is also a simple case like the previous one (http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space). I am presenting the code. But something I need to explain.

    okfn
    

    must be called like

    okfn(skb);
    

    And it will free the skb itself. And my problem in the question was about doubly freeing an skb. Look in the following code and it will be understood what is needed to get it done. The code is just used for testing purpose. The first 5 bytes (and plus a '\0') will be used to build a new packet, and rest of the data is used to create the second one. So, here we go. Necessary helper functions for printing skb info, ip header info etc. are provided for convenience (which I used for understanding what is going on).

    #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");
    

    So...As I am new in kernel space programming, any suggestions are welcome for improvement.

    0 讨论(0)
提交回复
热议问题