在 linux 内核中发送数据包
send packet in linux kernel
我在kernel-space中写了一个发送数据包的模块。但在 insmod
之后它给出了分段错误。我尝试更改其中的某些部分,但仍然出现错误。
代码:
//libraries
#define IP_Header_RM 20
#define UDP_Header_RM 8
static int __init init_Module(void){
unsigned char *Data = "Test_Packet";
int i = strlen(Data);
struct sk_buff* skb = alloc_skb(ETH_HLEN + IP_Header_RM + UDP_Header_RM + i, GFP_ATOMIC);
struct iphdr* iph = (struct iphdr*)skb_push(skb, IP_Header_RM);
struct ethhdr* eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));
struct udphdr* uh = (struct udphdr*)skb_push(skb, UDP_Header_RM);
struct net_device *Device;
uint16_t proto;
uint8_t Mac_Addr[ETH_ALEN] = {0x38, 0xd5, 0x47, 0xa1, 0x07, 0x41};
Data = skb_put(skb, i);
skb_reserve(skb, ETH_HLEN);
Device = dev_get_by_name(&init_net,"enp0s3");
proto = ETH_P_IP;
uh->len = htons(i);
uh->source = htons(2121);
uh->dest = htons(2121);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len= htons(IP_Header_RM + i);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = 19216805;
iph->daddr = 19216804;
skb->protocol = eth->h_proto = htons(proto);
skb->no_fcs = 1;
memcpy(eth->h_source, Device->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, Mac_Addr, ETH_ALEN);
skb->pkt_type = PACKET_OUTGOING;
dev_queue_xmit(skb);
return 1;
}
static void __exit exit_Module(void){
printk(KERN_INFO "Done");
}
module_init(init_Module);
module_exit(exit_Module);
我错了哪些部分?
提前致谢
您需要先在分配的缓冲区上执行 skb_reserve(),然后再对用户数据执行任何 skb_put() 调用或对 [=28= 执行 skb_push() ] headers。您首先尝试 skb_push() 在没有适当保留的缓冲区上进行段错误。我还为您提供了其他一些建议:
- 下次包括您的完整来源!
- 重新排列您推送的 header 的顺序以制作合法的 UDP/IP 数据包
- dev_get_by_name() 可能会失败;在尝试 memcpy 到它的缓冲区之前应该检查
- 在任何 eth/IP header(s)
之前推送用户数据
- Return 模块的 init() 中的 0 而不是 1 表示成功
像这样的教程页面可能有助于将所有内容放在一起:http://vger.kernel.org/~davem/skb_data.html
下面的代码在我的带有 4.19 Linux 内核的 Debian 10 系统上没有出现段错误。
//libraries
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
#define IP_Header_RM 20
#define UDP_Header_RM 8
static int __init init_Module(void){
unsigned char *Data = "Test_Packet";
int i = strlen(Data);
struct sk_buff* skb = alloc_skb(ETH_HLEN + IP_Header_RM + UDP_Header_RM + i, GFP_ATOMIC);
struct net_device *Device;
uint16_t proto;
struct iphdr* iph;
struct ethhdr* eth;
struct udphdr* uh;
uint8_t Mac_Addr[ETH_ALEN] = {0x38, 0xd5, 0x47, 0xa1, 0x07, 0x41};
skb_reserve(skb, ETH_HLEN + IP_Header_RM + UDP_Header_RM + i);
Data = skb_put(skb, i);
iph = (struct iphdr*)skb_push(skb, IP_Header_RM);
uh = (struct udphdr*)skb_push(skb, UDP_Header_RM);
eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));
Device = dev_get_by_name(&init_net,"enp0s3");
if (Device == NULL) {
printk(KERN_INFO "init_Module: no such device enp0s3\n");
return 1;
}
proto = ETH_P_IP;
uh->len = htons(i);
uh->source = htons(2121);
uh->dest = htons(2121);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len= htons(IP_Header_RM + i);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = 19216805;
iph->daddr = 19216804;
skb->protocol = eth->h_proto = htons(proto);
skb->no_fcs = 1;
memcpy(eth->h_source, Device->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, Mac_Addr, ETH_ALEN);
skb->pkt_type = PACKET_OUTGOING;
dev_queue_xmit(skb);
return 0;
}
static void __exit exit_Module(void){
printk(KERN_INFO "Done");
}
module_init(init_Module);
module_exit(exit_Module);
MODULE_DESCRIPTION("Stack Overflow 66846959");
MODULE_LICENSE("GPL");
我在kernel-space中写了一个发送数据包的模块。但在 insmod
之后它给出了分段错误。我尝试更改其中的某些部分,但仍然出现错误。
代码:
//libraries
#define IP_Header_RM 20
#define UDP_Header_RM 8
static int __init init_Module(void){
unsigned char *Data = "Test_Packet";
int i = strlen(Data);
struct sk_buff* skb = alloc_skb(ETH_HLEN + IP_Header_RM + UDP_Header_RM + i, GFP_ATOMIC);
struct iphdr* iph = (struct iphdr*)skb_push(skb, IP_Header_RM);
struct ethhdr* eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));
struct udphdr* uh = (struct udphdr*)skb_push(skb, UDP_Header_RM);
struct net_device *Device;
uint16_t proto;
uint8_t Mac_Addr[ETH_ALEN] = {0x38, 0xd5, 0x47, 0xa1, 0x07, 0x41};
Data = skb_put(skb, i);
skb_reserve(skb, ETH_HLEN);
Device = dev_get_by_name(&init_net,"enp0s3");
proto = ETH_P_IP;
uh->len = htons(i);
uh->source = htons(2121);
uh->dest = htons(2121);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len= htons(IP_Header_RM + i);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = 19216805;
iph->daddr = 19216804;
skb->protocol = eth->h_proto = htons(proto);
skb->no_fcs = 1;
memcpy(eth->h_source, Device->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, Mac_Addr, ETH_ALEN);
skb->pkt_type = PACKET_OUTGOING;
dev_queue_xmit(skb);
return 1;
}
static void __exit exit_Module(void){
printk(KERN_INFO "Done");
}
module_init(init_Module);
module_exit(exit_Module);
我错了哪些部分?
提前致谢
您需要先在分配的缓冲区上执行 skb_reserve(),然后再对用户数据执行任何 skb_put() 调用或对 [=28= 执行 skb_push() ] headers。您首先尝试 skb_push() 在没有适当保留的缓冲区上进行段错误。我还为您提供了其他一些建议:
- 下次包括您的完整来源!
- 重新排列您推送的 header 的顺序以制作合法的 UDP/IP 数据包
- dev_get_by_name() 可能会失败;在尝试 memcpy 到它的缓冲区之前应该检查
- 在任何 eth/IP header(s) 之前推送用户数据
- Return 模块的 init() 中的 0 而不是 1 表示成功
像这样的教程页面可能有助于将所有内容放在一起:http://vger.kernel.org/~davem/skb_data.html 下面的代码在我的带有 4.19 Linux 内核的 Debian 10 系统上没有出现段错误。
//libraries
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/scatterlist.h>
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
#define IP_Header_RM 20
#define UDP_Header_RM 8
static int __init init_Module(void){
unsigned char *Data = "Test_Packet";
int i = strlen(Data);
struct sk_buff* skb = alloc_skb(ETH_HLEN + IP_Header_RM + UDP_Header_RM + i, GFP_ATOMIC);
struct net_device *Device;
uint16_t proto;
struct iphdr* iph;
struct ethhdr* eth;
struct udphdr* uh;
uint8_t Mac_Addr[ETH_ALEN] = {0x38, 0xd5, 0x47, 0xa1, 0x07, 0x41};
skb_reserve(skb, ETH_HLEN + IP_Header_RM + UDP_Header_RM + i);
Data = skb_put(skb, i);
iph = (struct iphdr*)skb_push(skb, IP_Header_RM);
uh = (struct udphdr*)skb_push(skb, UDP_Header_RM);
eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));
Device = dev_get_by_name(&init_net,"enp0s3");
if (Device == NULL) {
printk(KERN_INFO "init_Module: no such device enp0s3\n");
return 1;
}
proto = ETH_P_IP;
uh->len = htons(i);
uh->source = htons(2121);
uh->dest = htons(2121);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len= htons(IP_Header_RM + i);
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
iph->saddr = 19216805;
iph->daddr = 19216804;
skb->protocol = eth->h_proto = htons(proto);
skb->no_fcs = 1;
memcpy(eth->h_source, Device->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, Mac_Addr, ETH_ALEN);
skb->pkt_type = PACKET_OUTGOING;
dev_queue_xmit(skb);
return 0;
}
static void __exit exit_Module(void){
printk(KERN_INFO "Done");
}
module_init(init_Module);
module_exit(exit_Module);
MODULE_DESCRIPTION("Stack Overflow 66846959");
MODULE_LICENSE("GPL");