协议栈构造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));