将小型 UDP 数据包从 Linux 内核发送到 LOOPBACK [英] Sending small UDP packets from the Linux Kernel to LOOPBACK

查看:22
本文介绍了将小型 UDP 数据包从 Linux 内核发送到 LOOPBACK的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况:我的代码基本上被入侵到 Linux 内核的驱动程序中.我想在用户空间中的应用程序被触发到主系统之前通知它们值得注意的原始事件.

Situation: My code is basically hacked into a driver of the Linux Kernel. I want to notify an application in user space about noteworthy raw events before they get fired off to the main system.

解决方案的步骤:我在这里找到了一个从内核空间发送 UDP 数据包的好例子:http://kernelnewbies.org/Simple_UDP_Server.他们使用 INADDR_LOOPBACK 作为目标地址,这正是我想要的.

Steps for Solution: I found a nice example for a sending UDP packets from Kernel space here: http://kernelnewbies.org/Simple_UDP_Server. They use INADDR_LOOPBACK as target address which is exactly what I want.

由于这是中断上下文,我决定使用工作队列来发送数据包(我得到了 BUG:在没有它的情况下进行原子调度).所以我的发送代码是基于封装在工作队列结构中的 kernelnewbies 代码,并在主进程上使用 INIT_WORK 和 schedule_work 触发.我没有声明我自己的工作队列.

As this is interrupt context I decided to use a work queue to send the packets (I got BUG: Scheduling while atomic without it). So my sending code is based on the kernelnewbies code wrapped into a work queue struct fired off with INIT_WORK and schedule_work on the main process. I am not declaring my own work queue.

我没有使用 Netpoll API 作为 this Question 建议无法从本地主机发送数据或向本地主机发送数据.你不能发送给自己"

I am not using the Netpoll API as this Question suggests it is not possible to send data from and to localhost. "You can't send to yourself"

问题:从内核发送的数据和从我的 UDP 接收器接收的数据很少匹配.我不知道为什么会这样.

Problem: The data sent from Kernel and received from my UDP receiver do rarely match. I have no idea why this happens.

用于测试的虚拟数据代码,包括工作队列结构的定义:

Code for the dummy data for testing including the definition of the struct for the work queue:

static struct socket *sock_send;
static struct sockaddr_in addr_send;

static struct ksocket_workmessage {
    unsigned char *buf;
    int len;
    struct work_struct workmessage;
} workmsg;


unsigned char testmsg[] = {'T', 'e', 's', 't', 'i', 'n', 'g', 'm', 's', 'g', ''};
workmsg.buf = testmsg;
workmsg.len = 11;
INIT_WORK(&workmsg.workmessage, handle_workmessage);
schedule_work(&workmsg.workmessage);

发送实际数据包类似于 kernelnewbies 示例中的int ksocket_send".唯一的区别是我的 send_socket 是静态的,我必须从工作队列中获取带有 container_of 的 buf 和 len.我在一个完全静态的环境中工作.我的 handle_workmessage 方法也是静态的:

Sending the actual packet is like "int ksocket_send" from the kernelnewbies example. Only difference is that my send_socket is static and that I have to get buf and len with container_of from the work queue. I am working in a completely static context. My handle_workmessage method is also static:

static void handle_workmessage(struct work_struct *work)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        struct ksocket_workmessage *workmsg = container_of(work, struct ksocket_workmessage, workmessage);


        if (sock_send->sk==NULL)
             return;

        iov.iov_base = workmsg->buf;
        iov.iov_len = workmsg->len;

        msg.msg_flags = 0;
        msg.msg_name = &addr_send;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_sendmsg(sock_send,&msg,workmsg->len);
        set_fs(oldfs);
}

接收端如下所示:

int main(int argc, char**argv)
{
int sockfd,n;
struct sockaddr_in servaddr;
socklen_t len;
unsigned char mesg[1000];

sockfd=socket(AF_INET,SOCK_DGRAM,0);

bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(REC_PORT);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

for (;;)
{
  n = recv(sockfd,mesg,1000,0);
  printf("-------------------------------------------------------
");
  mesg[n] = 0;
  printf("Received the following: %d bytes
", n);
  printf("%s",mesg);
  printf("%c",mesg[0]);
  printf(",%c",mesg[1]);
  printf(",%c",mesg[2]);
  printf(",%c",mesg[3]);
  printf(",%c",mesg[4]);
  printf(",%c",mesg[5]);
  printf(",%c",mesg[6]);
  printf(",%c",mesg[7]);
  printf(",%c",mesg[8]);
  printf(",%c
",mesg[9]);
  //printf("%c
",mesg[0]);
  printf("-------------------------------------------------------
");
  memset(mesg, 0, sizeof(mesg));
 }
}

输出看起来已损坏,尽管我总是发送完全相同的消息用于测试目的:

The Output looks corrupted, even though that I always send the exact same message for testing purpose:

-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
����d����,�,�,�,d,�,�,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,�,�,�,�,2,k,�,�,�
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�<����,<,�,�,�,,,,
                    ,=
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes


,,%,�,,,,,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
 ����Vk��1k ,�,�,�,�,V,k,�,�,1
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
TestingmsgT,e,s,t,i,n,g,m,s,g
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,,,,�,,�,,
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
,,
  ,�,,,,,�,<
-------------------------------------------------------
-------------------------------------------------------
Received the following: 11 bytes
�}|�ingmsg�,},|,�,i,n,g,m,s,g
-------------------------------------------------------

这可能是什么原因?由于它有时适用于预期的输出TestingmsgT,e,s,t,i,n,g,m,s,g",因此它不应该是技术限制.数据包碎片也不应该发生,因为我只发送 11 个字节.也没有丢包.每次我发送数据包时,它也会收到.

What could be the reason for this? As it works sometimes with the expected output "TestingmsgT,e,s,t,i,n,g,m,s,g", it shouldn't be a technical restriction. Packet fragmentation should also not happen as I only send 11 bytes. There is also no packet loss. Everytime I am sending the packet, it is also received.

更新:它可以工作.. 但我不知道为什么首先,感谢alk 的评论,我忘记了这一点.在发送数据之前记录.我在调用 schedule_work 之前做了记录.现在我直接登录我的发送方法 workmsg->buf,甚至在存储到来自 iov 的 void * 指针之前.那里的数据已经损坏了.

UPDATE: IT WORKS.. but I don't know why first, thanks for the comment from alk, that I forgot the obvious. To log just before the data is sent. I did log before calling schedule_work. Now I log directly in my send method workmsg->buf before even stored to the void * pointer from iov. The data is already corupted there.

结构体 ksocket_workmessage 有一个 char *,我的数据是 char [] 并被分配给结构体的指针.

The struct ksocket_workmessage had a char *, my data was char [] and got assigned to the pointer of the struct.

我现在所做的是更改我的 struct ksocket_workmessage 中的数据类型:

What I did now is to change the data type within my struct ksocket_workmessage:

struct ksocket_workmessage {
        unsigned char buf[11];
        int len;
        struct work_struct workmessage;
} workmsg;

由于没有指针,无法创建 unsigned char testmsg[],所以直接分配 buf:

As I don't have a pointer anymore, I could not create my unsigned char testmsg[], so I went for assigning buf directly:

workmsg.buf[0] = 'T';
workmsg.buf[1] = 'e';
workmsg.buf[2] = 's';
workmsg.buf[3] = 't';
workmsg.buf[4] = 'i';
workmsg.buf[5] = 'n';
workmsg.buf[6] = 'g';
workmsg.buf[7] = 'm';
workmsg.buf[8] = 's';
workmsg.buf[9] = 'g';
workmsg.buf[10] = '';

如果有人能告诉我我最初的方法在哪里失败,我很乐意接受它作为正确答案.

If anyone could tell me where my initial approach failed I will gladly accept it as the correct answer.

推荐答案

由于它有时有效,有时无效,我建议问题是您正在查看已释放 ()d 的内存.因此,内容有时是正确的,有时是错误的.由于您的本地缓冲区很好,因此必须在将其复制到本地内存之前在内核中发生.

Since it sometimes works and sometimes doesn't I'd suggest the problem is that you are looking at memory which has been free()d. Thus the contents are sometimes correct and sometimes they are mangled. Since your local buffer is fine this must be occurring in the kernel before it is copied to local memory.

确实是unsigned char testmsg[]声明为局部变量吗?

Indeed is the unsigned char testmsg[] declared as a local variable?

由于没有立即发送消息,因此您传递的 testmsg 地址在堆栈上.如果有后续的函数调用,那么它们将在发送消息之前覆盖消息的内容.然后您有时会看到正确的消息,有时则不会.视工作安排而定.

Since the message isn't sent straight away the testmsg address that you pass is on the stack. If there are subsequent functional calls then they will over write the contents of the message before it is sent. Then you will sometimes see the correct message and sometimes not. Depending on the scheduling of the work.

这篇关于将小型 UDP 数据包从 Linux 内核发送到 LOOPBACK的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆