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

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

问题描述

情况:我的代码基本上被黑客入侵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用作此问题建议无法从本地主机发送数据或向本地主机发送数据. 你不能寄给自己"

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', '\0'};
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("-------------------------------------------------------\n");
  mesg[n] = 0;
  printf("Received the following: %d bytes\n", 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\n",mesg[9]);
  //printf("%c\n",mesg[0]);
  printf("-------------------------------------------------------\n");
  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.

我现在要做的是更改结构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;

由于我不再有指针,因此无法创建我的未签名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] = '\0';

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

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

推荐答案

由于它有时可以工作,有时不起作用,所以我建议问题是您正在查看已被free()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.

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

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