Using Netfilter's hooks (NF_INET_PRE_ROUTING and NF_INET_POST_ROUTING) I implemented a kernel module that monitors all incoming and outgoing packets for a given host. By looking at the skuffs I can classify packets and identify those that I am interested in. Each time I detect such packets I want to generate my own packet and send it out in the network (note: I am not copying/cloning the original packet but instead create one from "scratch" and send it out using dev_queue_xmit. The only similarity with the original packet is that my packet goes towards the same destination, but has different port/protocol etc.).
使用Netfilter的钩子(NF_INET_PRE_ROUTING和NF_INET_POST_ROUTING)我实现了一个内核模块,它监视给定主机的所有传入和传出数据包。通过查看skuff,我可以对数据包进行分类并识别我感兴趣的数据包。每次检测到这些数据包时,我都想生成自己的数据包并将其发送到网络中(注意:我不是在复制/克隆原始数据包但是从“scratch”创建一个并使用dev_queue_xmit将其发送出去。与原始数据包的唯一相似之处在于我的数据包走向同一目的地,但具有不同的端口/协议等。
The problem is that my generated packets are being sent out with empty payload. Packets successfully reach the destination, the size of the payload is correct, but its content is all set to zeros. Two observations: (1) The function that I am using to construct skbuffs and send out has been tested before and seemed to work. (2) The problem appear only when I classify outgoing packets and attempt to send my own along the way, seemingly the same code works fine when I classify packets using NF_INET_PRE_ROUTING.
问题是我生成的数据包是以空载荷发送出去的。数据包成功到达目的地,有效负载的大小是正确的,但其内容全部设置为零。两个观察结果:(1)我用来构建skbuff并发送出去的功能之前已经过测试并且似乎有效。 (2)只有当我对传出的数据包进行分类并尝试自己发送时,问题才会出现,当我使用NF_INET_PRE_ROUTING对数据包进行分类时,看起来相同的代码工作正常。
Please see the code below:
请参阅以下代码:
static struct nf_hook_ops nfout;
static int __init init_main(void) {
nfout.hook = hook_func_out;
nfout.hooknum = NF_INET_POST_ROUTING;
nfout.pf = PF_INET;
nfout.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfout);
printk(KERN_INFO "Loading Postrouting hook\n");
return 0;
}
static unsigned int hook_func_out(const struct nf_hook_ops *ops,
struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, int (*okfn)(struct sk_buff *)) {
if (skb is the packet that I am looking for, omitting details...) {
generate_send_packet(skb);
}
return NF_ACCEPT;
}
void generate_send_packet(struct sk_buff *target_skb) {
static struct tcphdr * tcph;
static struct iphdr * iph;
static struct ethhdr * ethh;
struct sk_buff * skb1;
iph = ip_hdr(target_skb);
tcph = tcp_hdr(target_skb);
ethh = eth_hdr(target_skb);
int payload = 123456789;
skb1 = construct_udp_skb(dev,
dev->dev_addr, mac,
iph->saddr, iph->daddr,
ntohs(tcph->source), dst_port,
(unsigned char *)&payload, sizeof(int)
);
if (dev_queue_xmit(skb1) != NET_XMIT_SUCCESS) {
printk(KERN_INFO "Sending failed\n");
}
}
struct sk_buff* construct_udp_skb(struct net_device *dev,
unsigned char * src_mac, unsigned char * dst_mac,
uint32_t src_ip, uint32_t dst_ip,
uint32_t src_port, uint32_t dst_port,
uint32_t ttl, uint32_t tcp_seq,
unsigned char * usr_data, uint16_t usr_data_len) {
static struct ethhdr *ethh;
static struct iphdr *iph;
struct udphdr * udph;
static struct sk_buff *skb;
static uint16_t header_len = 300;
unsigned char * p_usr_data;
int udplen;
skb = alloc_skb(1000, GFP_KERNEL);
skb_reserve(skb, header_len);
//-----------------------------------------------
udph = (struct udphdr*) skb_push(skb, sizeof(struct udphdr));
iph = (struct iphdr*) skb_push(skb, sizeof(struct iphdr));
ethh = (struct ethhdr*) skb_push(skb, sizeof(struct ethhdr));
memset(udph, 0 , sizeof(struct udphdr));
memset(iph, 0 , sizeof(struct iphdr));
skb_set_mac_header(skb, 0);
skb_set_network_header(skb, sizeof(struct ethhdr));
skb_set_transport_header(skb, sizeof(struct ethhdr) + sizeof(struct iphdr));
//ETH -------------------------------------------
memcpy(ethh->h_source, src_mac, 6);
memcpy(ethh->h_dest, dst_mac, 6);
ethh->h_proto = htons(ETH_P_IP);
//IP --------------------------------------------
iph->ihl = 5;
iph->version = 4;
iph->ttl = 128;
iph->tos = 0;
iph->protocol = IPPROTO_UDP;
iph->saddr = src_ip;
iph->daddr = dst_ip;
iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
iph->id = htons(222);
iph->frag_off = 0;
iph->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + usr_data_len );
ip_send_check(iph);
//UDP--------------------------------------------
udph->source = htons(src_port);
udph->dest = htons(dst_port);
skb->dev = dev;
skb->protocol = IPPROTO_UDP;
skb->priority = 0;
skb->pkt_type = PACKET_OUTGOING;
p_usr_data = skb_put(skb, usr_data_len);
printk(KERN_INFO "Sending [%i]\n", *(int*)usr_data);
skb->csum = csum_and_copy_from_user(usr_data, p_usr_data, usr_data_len, 0, &err);
udplen = sizeof(struct udphdr) + usr_data_len;
udph->len = htons(udplen);
udph->check = udp_v4_check(udplen,
iph->saddr, iph->daddr,
0);
return skb;
}
What could be the possible reason why dev_queue_xmit would nullify the payload in the skbuff?
dev_queue_xmit可能会使skbuff中的有效负载无效,这可能是什么原因?
Thanks!
1 个解决方案
#1
-1
I assume that the result of debug print message for printk(KERN_INFO "Sending [%i]\n", (int)usr_data) is as expected. But what about the skb->data? Can you try to print it after csum_and_copy_from_user() to see whether it is empty or not? It seems very likely that you will see the zero payload at this point already.
我假设printk的调试打印消息的结果(KERN_INFO“发送[%i] \ n”,(int)usr_data)是预期的。但是skb->数据怎么样?您可以尝试在csum_and_copy_from_user()之后打印它以查看它是否为空?看来你很可能已经在这一点上看到零负载。
#1
-1
I assume that the result of debug print message for printk(KERN_INFO "Sending [%i]\n", (int)usr_data) is as expected. But what about the skb->data? Can you try to print it after csum_and_copy_from_user() to see whether it is empty or not? It seems very likely that you will see the zero payload at this point already.
我假设printk的调试打印消息的结果(KERN_INFO“发送[%i] \ n”,(int)usr_data)是预期的。但是skb->数据怎么样?您可以尝试在csum_and_copy_from_user()之后打印它以查看它是否为空?看来你很可能已经在这一点上看到零负载。