Ich versuche, ein Linux-Kernel-Modul zu schreiben, das über Netlink mit dem Benutzerprozess kommuniziert. Ich verwende Netlink, weil das Benutzerprogramm, mit dem ich kommunizieren möchte, nur über Sockets kommuniziert und ich das nicht ändern kann, um es hinzuzufügen ioctl()
oder irgendwas.
Das Problem ist, dass ich nicht herausfinden kann, wie das geht. Ich habe gegoogelt, aber alle Beispiele, die ich gefunden habe, sind für alt wie Dieses hier und für aktuelle Kernel-Versionen nicht mehr gültig. Ich habe mir diese SO-Frage auch angesehen, aber das Beispiel hier verwendet libnl für Socket-Operationen, aber ich möchte mich an Standard-Socket-Funktionen halten (definiert durch sys/socket.h
). Kann mich also bitte jemand hier zu einem Tutorial oder einer Anleitung oder etwas führen, das mir helfen kann, die Benutzeroberfläche und die Verwendung von Netlink zu verstehen? Ich würde ein funktionierendes Beispiel sehr schätzen, nichts Besonderes, nur ein sehr einfaches Beispiel dafür, wie man eine Verbindung von einem Socket im Benutzerprogramm zu einem Socket im Kernel herstellt und dann Daten vom Benutzerprozess an den Kernel sendet und vom Kernel zurückerhält.
Sagen Sie mir bitte auch nicht, ich solle mir den Kernel-Code ansehen. Ich mache es bereits, aber es wird viel Zeit in Anspruch nehmen und ich habe nicht mehr viel davon übrig.
Aktualisieren:
Nach viel Versuch und Irrtum habe ich folgenden Code, der eine Nachricht vom Benutzerprogramm an den Kernel sendet, aber die Nachricht vom Kernel an das Benutzerprogramm, dh mit netlink_unicast()
funktioniert nicht. Es funktioniert nicht nur nicht, der Anruf hängt die Systeme und dann muss ich die Maschine neu starten. Kann jemand bitte einen Blick darauf werfen und mir sagen, was ich falsch mache. Das netlink_unicast()
Aufruf wird im folgenden Code kommentiert. Es sollte für Kernel-zu-Benutzerprogramm-Meldungen unkommentiert sein.
Benutzerprogramm
#include <sys/socket.h>
#include <linux/netlink.h>
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
void main()
{
sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
if(sock_fd<0)
return -1;
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
/* interested in group 1<<0 */
bind(sock_fd, (struct sockaddr*)&src_addr,
sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
nlh = (struct nlmsghdr *)malloc(
NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Sending message to kernel\n");
sendmsg(sock_fd,&msg,0);
printf("Waiting for message from kernel\n");
/* Read message from kernel */
recvmsg(sock_fd, &msg, 0);
printf(" Received message payload: %s\n",
NLMSG_DATA(nlh));
close(sock_fd);
}
Kernel-Code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#define NETLINK_USER 31
struct sock *nl_sk = NULL;
static void hello_nl_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int pid;
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink received msg payload: %s\n",
(char*)NLMSG_DATA(nlh));
pid = nlh->nlmsg_pid; /*pid of sending process */
NETLINK_CB(skb).dst_group = 0; /* not in mcast group */
NETLINK_CB(skb).pid = 0; /* from kernel */
//NETLINK_CB(skb).groups = 0; /* not in mcast group */
//NETLINK_CB(skb).dst_pid = pid;
printk("About to send msg bak:\n");
//netlink_unicast(nl_sk,skb,pid,MSG_DONTWAIT);
}
static int __init hello_init(void)
{
printk("Entering: %s\n",__FUNCTION__);
nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0,
hello_nl_recv_msg, NULL, THIS_MODULE);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "exiting hello module\n");
netlink_kernel_release(nl_sk);
}
module_init(hello_init);
module_exit(hello_exit);
Wie können 10 Personen dies als Favorit markieren, aber nur 5 Personen stimmen dafür?
– Donal Lafferty
4. September 2013 um 15:10 Uhr
Ich weiß, es ist ein bisschen spät, aber dieses Buch (Kap. 2) behandelt auch Netlink-Sockets: amazon.com/Linux-Kernel-Networking-Implementation-Experts/dp/…
– holgac
1. April 2015 um 14:38 Uhr
dieses Anwenderprogramm arbeitet solange
struct msghdr msg;
ist im globalen Geltungsbereich definiert. Aber sobald ich das in eine Funktion (z. B. main) verschiebe, funktioniert das Benutzerprogramm nicht mehr undsendmsg
gibt -1 zurück und errno wird auf Fehler 105 gesetzt (ENOBUFS – kein Pufferplatz verfügbar). Kann jemand erklären warummsghdr
funktioniert nur, wenn global in diesem Programm definiert?– Ungeklebt
12. März 2019 um 23:26 Uhr