2012-05-08 16 views
15

Anche se un argomento simile esiste già, ho notato che risale a due anni, quindi credo che sia più opportuno aprire uno nuovo ...L'invio di pacchetti UDP dal Linux Kernel

sto cercando di capire come inviare pacchetti UDP dal kernel di Linux (3.3.4), per monitorare il comportamento del generatore di numeri casuali (/drivers/char/random.c). Finora, sono riuscito a monitorare alcune cose grazie alle funzioni sock_create e sock_sendmsg. È possibile trovare il tipico pezzo di codice che uso alla fine di questo messaggio. (Si potrebbe anche voler scaricare il file random.c completo modificato here.)

Inserendo questo codice all'interno delle appropriate funzioni random.c, sono in grado di inviare un pacchetto UDP per ogni accesso a/dev/random e/dev/urandom e ogni evento tastiera/mouse usato dal generatore di numeri casuali per raccogliere entropia. Tuttavia non funziona affatto quando provo a monitorare gli eventi del disco: genera un panico del kernel durante l'avvio.

Di conseguenza, ecco la mia domanda principale: Hai idea del motivo per cui il mio codice causa così tanti problemi quando inserito nella funzione eventi del disco? (add_disk_randomness)

In alternativa, ho letto sull'API netpoll, che dovrebbe gestire questo tipo di problemi UDP-in-kernel. Sfortunatamente non ho trovato alcuna documentazione rilevante a parte una presentazione Red Hat abbastanza interessante ma datata del 2005. Pensi che dovrei usare questa API? Se sì, hai qualche esempio?

Qualsiasi aiuto sarebbe apprezzato. Grazie in anticipo.

PS: E 'la mia prima domanda qui, quindi per favore non esitate a dirmi se sto facendo qualcosa di sbagliato, lo terrò a mente per il futuro :)


#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

Generalmente, è preferibile non fare nulla nel kernel che si possa fare in userspace - sarebbe probabilmente meglio esporre le informazioni nello spazio utente tramite meccanismi di registrazione o sysfs e poi avere un demone che lo invia al sistema remoto . –

+0

Quando esiste già un argomento simile, collegarlo ad esso. Hai svolto un lavoro ragionevole spiegando perché ritieni che la domanda esistente non sia abbastanza valida (avrei potuto dire qualcosa sulla versione del kernel più recente, ecc.). Ma avere la domanda esistente facilmente disponibile rende possibile che le risposte si concentrino su ciò che è cambiato da allora. –

+0

@BenVoigt Thx per il vostro consiglio. Ecco [argomento precedente] (http://stackoverflow.com/questions/1814485/sending-udp-packet-in-linux-kernel). – tvuillemin

risposta

13

ho risolto il mio problema a pochi mesi fa. Ecco la soluzione che ho usato.

L'API di invio pacchetti standard (sock_create, connect, ...) non può essere utilizzata in alcuni contesti (interruzioni). Usarlo nel posto sbagliato porta a un KP.

L'API netpoll è più "di basso livello" e funziona in ogni contesto. Tuttavia, ci sono diverse condizioni:

  • dispositivi Ethernet
  • rete IP
  • solo UDP (non TCP)
  • diversi computer per l'invio e la ricezione di pacchetti (Non è possibile inviare a te stesso.

Assicurati di rispettarli, perché non riceverai alcun messaggio di errore se c'è un problema. Fallirà silenziosamente :) Ecco un po 'di codice.

Dichiarazione

#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; 

inizializzazione

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; 

Usa

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

Spero che possa aiutare qualcuno.

+0

come sollevato [qui] (http://stackoverflow.com/questions/35880786/why-do-i-get-this-error), la versione del kernel 3.9 (aprile 2013) ha apportato una modifica inattuale a 'linux/netpoll.h 'Quindi questo codice non è più compilato –

0

Il panico durante l'avvio potrebbe essere causato dal tentativo di utilizzare qualcosa che non è stato ancora inizializzato. Guardare la traccia dello stack potrebbe aiutare a capire cosa è realmente accaduto.

Per quanto riguarda il tuo problema, penso che tu stia cercando di fare una cosa semplice, quindi perché non restare con semplici strumenti? ;) le stampe potrebbero essere una cattiva idea, ma dare trace_printk a partire. trace_printk è parte dell'infrastruttura Ftrace.

Sezione Utilizzando traccia _printk() nel seguente articolo dovrebbe insegnare tutto ciò che c'è da sapere: http://lwn.net/Articles/365835/

Problemi correlati