• 协议栈构造skb发送udp


    /**
     * @file    lkm.c
     * @author  Dmytro Shytyi
     * @date    14 Octobre 2018
     * @version 0.1
     * @brief  A "Hello World!" loadable kernel module (LKM) that sends Hello World udp packet.
     * @see https://dmytro.shytyi.net/ for a full description and follow-up descriptions.
    */
     
    #include <linux/init.h>             // Macros used to mark up functions e.g., __init __exit
    #include <linux/module.h>           // Core header for loading LKMs into the kernel
    #include <linux/kernel.h>           // Contains types, macros, functions for the kernel
    
    #include <linux/types.h>
    #include <linux/sched.h>
    #include <linux/mm.h>
    #include <linux/fcntl.h>
    #include <linux/socket.h>
    #include <linux/in.h>
    #include <linux/inet.h>
    #include <linux/skbuff.h>
    #include <linux/if_arp.h>
    #include <linux/netdevice.h> 
    #include <linux/etherdevice.h>
    #include <linux/netdevice.h> 
    #include <linux/etherdevice.h>
    //#include <linux/string.h>
    #include <linux/ip.h> 
    #include <linux/udp.h>
    MODULE_LICENSE("GPL");              ///< The license type -- this affects runtime behavior
    MODULE_AUTHOR("Dmytro Shytyi");      ///< The author -- visible when you use modinfo
    MODULE_DESCRIPTION("A simple linux kernel module - send hello world packet.");  ///< The description -- see modinfo
    MODULE_VERSION("0.1");              ///< The version of the module
     
     
    static int send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto);
    
    static int __init helloLKM_init(void){
        uint16_t proto;
        static char addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
        uint8_t dest_addr[ETH_ALEN];
        struct net_device *enp0s3;
        enp0s3 = dev_get_by_name(&init_net,"enp0s3");
        memcpy(dest_addr, addr,ETH_ALEN);
        proto = ETH_P_IP;
        send_my(enp0s3,dest_addr,proto);
        printk(KERN_INFO "Hello from the  LKM!\n" );
       return 0;
    }
    
    unsigned int inet_addr(char *str)
    {
        int a, b, c, d;
        char arr[4];
        sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
        arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d;
        return *(unsigned int *)arr;
    }
    
    int
    send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto)
    {
      int            ret;
      unsigned char* data;
      
      char *srcIP = "192.168.0.1";
      char *dstIP = "192.168.0.2";
      char *hello_world = ">>> KERNEL sk_buff Hello World <<< by Dmytro Shytyi";
      int data_len = 51;
    
      int udp_header_len = 8;
      int udp_payload_len = data_len;
      int udp_total_len = udp_header_len+udp_payload_len;
    
      int ip_header_len = 20;
      int ip_payload_len = udp_total_len;
      int ip_total_len = ip_header_len + ip_payload_len;
    
    /* skb */
      struct sk_buff* skb = alloc_skb(ETH_HLEN+ip_total_len, GFP_ATOMIC);//allocate a network buffer
      skb->dev = dev;
      skb->pkt_type = PACKET_OUTGOING;
      skb_reserve(skb, ETH_HLEN+ip_header_len+udp_header_len);//adjust headroom
    /* allocate space to data and write it */
      data = skb_put(skb,udp_payload_len);
      memcpy(data, hello_world, data_len);
    /* UDP header */
      struct udphdr* uh = (struct udphdr*)skb_push(skb,udp_header_len);
      uh->len = htons(udp_total_len);
      uh->source = htons(15934);
      uh->dest = htons(15904);
    
    /* IP header */
      struct iphdr* iph = (struct iphdr*)skb_push(skb,ip_header_len);
      iph->ihl = ip_header_len/4;//4*5=20 ip_header_len
      iph->version = 4; // IPv4u
      iph->tos = 0; 
      iph->tot_len=htons(ip_total_len); 
      iph->frag_off = 0; 
      iph->ttl = 64; // Set a TTL.
      iph->protocol = IPPROTO_UDP; //  protocol.
      iph->check = 0; 
      iph->saddr = inet_addr(srcIP);
      iph->daddr = inet_addr(dstIP);
    
      /*changing Mac address */
      struct ethhdr* eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));//add data to the start of a buffer
      skb->protocol = eth->h_proto = htons(proto);
      skb->no_fcs = 1;
      memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
      memcpy(eth->h_dest, dest_addr, ETH_ALEN);
     
    
      skb->pkt_type = PACKET_OUTGOING;
      ret = dev_queue_xmit(skb);
      return 1;
    } 
    
    static void __exit helloLKM_exit(void){
       printk(KERN_INFO "Goodbye from LKM!\n");
    }
     
    module_init(helloLKM_init);
    module_exit(helloLKM_exit);

    调用dev->netdev_ops->ndo_start_xmit发送直接机器挂掉

    解决checksum的问题

    [root@centos7 KERNEL-sk_buff-helloWorld]# cat lkm.c 
    /**
     * @file    lkm.c
     * @author  Dmytro Shytyi
     * @date    14 Octobre 2018
     * @version 0.1
     * @brief  A "Hello World!" loadable kernel module (LKM) that sends Hello World udp packet.
     * @see https://dmytro.shytyi.net/ for a full description and follow-up descriptions.
    */
     
    #include <linux/init.h>             // Macros used to mark up functions e.g., __init __exit
    #include <linux/module.h>           // Core header for loading LKMs into the kernel
    #include <linux/kernel.h>           // Contains types, macros, functions for the kernel
    
    #include <linux/types.h>
    #include <linux/sched.h>
    #include <linux/mm.h>
    #include <linux/fcntl.h>
    #include <linux/socket.h>
    #include <linux/in.h>
    #include <linux/inet.h>
    #include <linux/skbuff.h>
    #include <linux/if_arp.h>
    #include <linux/netdevice.h> 
    #include <linux/etherdevice.h>
    #include <linux/netdevice.h> 
    #include <linux/etherdevice.h>
    //#include <linux/string.h>
    #include <linux/ip.h> 
    #include <linux/udp.h>
    MODULE_LICENSE("GPL");              ///< The license type -- this affects runtime behavior
    MODULE_AUTHOR("Dmytro Shytyi");      ///< The author -- visible when you use modinfo
    MODULE_DESCRIPTION("A simple linux kernel module - send hello world packet.");  ///< The description -- see modinfo
    MODULE_VERSION("0.1");              ///< The version of the module
     
     
    static int send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto);
    
    static int __init helloLKM_init(void){
            uint16_t proto;
            static char addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
            uint8_t dest_addr[ETH_ALEN];
            struct net_device *enp125s0f0;
            enp125s0f0 = dev_get_by_name(&init_net,"enp125s0f0");
            memcpy(dest_addr, addr,ETH_ALEN);
            proto = ETH_P_IP;
            send_my(enp125s0f0,dest_addr,proto);
            printk(KERN_INFO "Hello from the  LKM!\n" );
       return 0;
    }
    
    unsigned int inet_addr(char *str)
    {
        int a, b, c, d;
        char arr[4];
        sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
        arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d;
        return *(unsigned int *)arr;
    }
    
    int
    send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto)
    {
      int            ret;
      unsigned char* data;
      
      char *srcIP = "10.10.6.251";
      char *dstIP = "10.10.6.82";
      char *hello_world = ">>> KERNEL sk_buff Hello World <<< by Dmytro Shytyi";
      int data_len = 51;
    
      int udp_header_len = 8;
      int udp_payload_len = data_len;
      int udp_total_len = udp_header_len+udp_payload_len;
    
      int ip_header_len = 20;
      int ip_payload_len = udp_total_len;
      int ip_total_len = ip_header_len + ip_payload_len;
    
    /* skb */
      struct sk_buff* skb = alloc_skb(ETH_HLEN+ip_total_len, GFP_ATOMIC);//allocate a network buffer
      skb->dev = dev;
      skb->pkt_type = PACKET_OUTGOING;
      skb_reserve(skb, ETH_HLEN+ip_header_len+udp_header_len);//adjust headroom
    /* allocate space to data and write it */
      data = skb_put(skb,udp_payload_len);
      memcpy(data, hello_world, data_len);
    /* UDP header */
      struct udphdr* uh = (struct udphdr*)skb_push(skb,udp_header_len);
      uh->len = htons(udp_total_len);
      uh->source = htons(15934);
      uh->dest = htons(15904);
    
    /* IP header */
      struct iphdr* iph = (struct iphdr*)skb_push(skb,ip_header_len);
      iph->ihl = ip_header_len/4;//4*5=20 ip_header_len
      iph->version = 4; // IPv4u
      iph->tos = 0; 
      iph->tot_len=htons(ip_total_len); 
      iph->frag_off = 0; 
      iph->ttl = 64; // Set a TTL.
      iph->protocol = IPPROTO_UDP; //  protocol.
      iph->check = 0; 
      iph->saddr = inet_addr(srcIP);
      iph->daddr = inet_addr(dstIP);
    
      /* caculate checksum */
      uh->check =0; 
      skb->csum = skb_checksum(skb, iph->ihl*4, skb->len - iph->ihl*4, 0);
      iph->check = ip_fast_csum(iph, iph->ihl);
      uh->check = csum_tcpudp_magic(inet_addr(srcIP), inet_addr(dstIP), skb->len - iph->ihl * 4, IPPROTO_UDP, skb->csum);
      skb->ip_summed = CHECKSUM_NONE;
    
    
      /*changing Mac address */
      struct ethhdr* eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));//add data to the start of a buffer
      skb->protocol = eth->h_proto = htons(proto);
      skb->no_fcs = 1;
      memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
      memcpy(eth->h_dest, dest_addr, ETH_ALEN);
     
    
      skb->pkt_type = PACKET_OUTGOING;
      //ret = dev->netdev_ops->ndo_start_xmit(dev,skb);
      ret = dev_queue_xmit(skb);
      return 1;
    } 
    
    static void __exit helloLKM_exit(void){
       printk(KERN_INFO "Goodbye from LKM!\n");
    }
     
    module_init(helloLKM_init);
    module_exit(helloLKM_exit);

     

    Tcpdump utility returns "truncated-ip" and "bytes missing" messages

     

    Question

    Why do you occasionally receive "truncated-ip" and "bytes missing" messages when running the tcpdump utility on your Network IPS appliance?

    Answer

    Tcpdump reports the truncated-ip and missing bytes message when the size of the IP packet (for example, IP header + TCP header + TCP payload) is shorter than the IP packet's total length indicator. The messages look like the following:

     原来是

    iph->tot_len =  ip_total_len;没有采用网络字节序

    iph->tot_len = htons(ip_total_len);

    proto UDP (17), length 54, bad cksum 81c8 (->8656)!)

    ip chekcsum只需要计算头部,而程序中计算了ip头 + udp头+ udp数据

    //Ip checksum
     改成
    iph->check = csum ((unsigned short *) (datagram + sizeof(struct ether_header)), sizeof (struct iphdr));

     

    Linux Kernel 下 udp packet 的收发(sk_buff+Netfiler)

  • 相关阅读:
    面试求职:数据库常见面试题(数据库优化思路)
    数据库优化面试内容
    nginx笔记-3
    webpack-问题记录
    [Tips] Linux查看系统环境变量
    解决input框中加入disabled="disabled"之后,改变字体的颜色(默认的是灰色)
    js 中日期转换成时间戳
    Day09_课程预览 Eureka Feign
    Day08_课程图片管理与分布式文件系统
    Day08_分布式文件系统FastDFS研究
  • 原文地址:https://www.cnblogs.com/dream397/p/15655323.html
Copyright © 2020-2023  润新知