2012-05-08 203 views
15

即使類似的話題已經存在,我注意到,它的歷史可以追溯到兩年了,因此,我想這是比較合適的,打開一個新的一個...從Linux內核發送UDP數據包

我想弄清楚如何從Linux Kernel(3.3.4)發送UDP數據包,以便監視隨機數生成器(/drivers/char/random.c)的行爲。到目前爲止,由於sock_create和sock_sendmsg函數的原因,我設法監視了一些東西。你可以在這封郵件的結尾找到我使用的典型代碼。 (您可能還想下載完整的修改過的隨機文件here。)

通過在適當的random.c函數中插入此代碼,我可以爲每個訪問發送一個UDP數據包到/ dev/random和/ dev/urandom,以及隨機數生成器用於收集熵的每個鍵盤/鼠標事件。但是,當我嘗試監視磁盤事件時,它根本不起作用:它在引導期間會產生內核恐慌。

因此,這裏是我的主要問題:你知道爲什麼我的代碼插入磁盤事件函數時會導致如此多的麻煩嗎?(add_disk_randomness)

另外,我已經讀過netpoll API,它應該可以處理這種UDP-in-kernel問題。不幸的是,除了2005年相當有趣但過時的紅帽演示外,我還沒有找到任何相關文檔。您認爲我應該使用此API嗎?如果是,你有任何例子嗎?

任何幫助,將不勝感激。 在此先感謝。

PS:這是我的第一個問題在這裏,所以請不要猶豫,告訴我,如果我做錯了,我會記住它的未來:)


#include <linux/net.h> 
#include <linux/in.h> 
#include <linux/netpoll.h> 
#define MESSAGE_SIZE 1024 
#define INADDR_SEND ((unsigned long int)0x0a00020f) //10.0.2.15 
static bool sock_init; 
static struct socket *sock; 
static struct sockaddr_in sin; 
static struct msghdr msg; 
static struct iovec iov; 

[...] 

int error, len; 
mm_segment_t old_fs; 
char message[MESSAGE_SIZE]; 

if (sock_init == false) 
{ 
    /* Creating socket */ 
    error = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); 
    if (error<0) 
    printk(KERN_DEBUG "Can't create socket. Error %d\n",error); 

    /* Connecting the socket */ 
    sin.sin_family = AF_INET; 
    sin.sin_port = htons(1764); 
    sin.sin_addr.s_addr = htonl(INADDR_SEND); 
    error = sock->ops->connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr), 0); 
    if (error<0) 
    printk(KERN_DEBUG "Can't connect socket. Error %d\n",error); 

    /* Preparing message header */ 
    msg.msg_flags = 0; 
    msg.msg_name = &sin; 
    msg.msg_namelen = sizeof(struct sockaddr_in); 
    msg.msg_control = NULL; 
    msg.msg_controllen = 0; 
    msg.msg_iov = &iov; 
    msg.msg_control = NULL; 
    sock_init = true; 
} 

/* Sending a message */ 
sprintf(message,"EXTRACT/Time: %llu/InputPool: %4d/BlockingPool: %4d/NonblockingPool: %4d/Request: %4d\n", 
    get_cycles(), 
    input_pool.entropy_count, 
    blocking_pool.entropy_count, 
    nonblocking_pool.entropy_count, 
    nbytes*8); 
iov.iov_base = message; 
len = strlen(message); 
iov.iov_len = len; 
msg.msg_iovlen = len; 
old_fs = get_fs(); 
set_fs(KERNEL_DS); 
error = sock_sendmsg(sock,&msg,len); 
set_fs(old_fs); 
+4

一般而言,最好不要在內核中執行任何可以在用戶空間中執行的操作 - 將信息通過日誌記錄機制或sysfs公開給用戶空間可能會更好,然後讓守護程序將其發送到遠程系統。 –

+0

當一個相似的話題已經存在時,鏈接到它。你做了一個合理的工作,解釋了爲什麼你認爲現有的問題不夠好(我可能會說一些關於新內核版本的內容等等)。但如果現有問題容易獲得,那麼答案就有可能集中於自那時起發生的變化。 –

+0

@BenVoigt Thx爲您的建議。這是[上一個主題](http://stackoverflow.com/questions/1814485/sending-udp-packet-in-linux-kernel)。 – tvuillemin

回答

13

我在幾個月前解決我的問題。這是我使用的解決方案。

標準數據包發送API(sock_create,connect,...)不能用於少數上下文(中斷)。在錯誤的地方使用它會導致KP。

netpoll API更「低級」,適用於各種環境。但是,有幾個條件:

  • 以太網設備
  • IP網絡
  • 只有UDP(無TCP)
  • 不同的計算機發送和接收數據包(您不能發送給自己。)

請務必尊重他們,因爲如果出現問題,您將不會收到任何錯誤消息。它只會默默地失敗:)這是一些代碼。

宣言

#include <linux/netpoll.h> 
#define MESSAGE_SIZE 1024 
#define INADDR_LOCAL ((unsigned long int)0xc0a80a54) //192.168.10.84 
#define INADDR_SEND ((unsigned long int)0xc0a80a55) //192.168.10.85 
static struct netpoll* np = NULL; 
static struct netpoll np_t; 

初始化

np_t.name = "LRNG"; 
strlcpy(np_t.dev_name, "eth0", IFNAMSIZ); 
np_t.local_ip = htonl(INADDR_LOCAL); 
np_t.remote_ip = htonl(INADDR_SEND); 
np_t.local_port = 6665; 
np_t.remote_port = 6666; 
memset(np_t.remote_mac, 0xff, ETH_ALEN); 
netpoll_print_options(&np_t); 
netpoll_setup(&np_t); 
np = &np_t; 

使用

char message[MESSAGE_SIZE]; 
sprintf(message,"%d\n",42); 
int len = strlen(message); 
netpoll_send_udp(np,message,len); 

希望它可以幫助別人。

+0

as raised [here](http://stackoverflow.com/questions/35880786/why-do-i-get-this-error),內核版本3.9(2013年4月)對'linux/netpoll.h '所以這段代碼不再編譯 –

0

引導過程中的恐慌可能是由於您嘗試使用尚未初始化的內容引起的。查看堆棧跟蹤可能有助於確定實際發生的情況。

至於你的問題,我認爲你正在嘗試做一件簡單的事情,那麼爲什麼不堅持簡單的工具? ;)printks確實可能是個不好的主意,但給trace_printk一個提示。 trace_printk是Ftrace基礎結構的一部分。

在下面的文章使用跟蹤 _printk()應該教你需要知道的一切: http://lwn.net/Articles/365835/