넷링크 소켓을 커널 모듈과 통신하는 방법?
넷링크를 이용해 사용자 프로세스와 소통하는 리눅스 커널 모듈을 쓰려고 한다.통신하려는 사용자 프로그램이 소켓만 사용하여 통신하고 추가하기 위해 변경할 수 없기 때문에 Netlink를 사용하고 있다.ioctl()
뭐 그런 거라도 말이야.
문제는 그것을 어떻게 하는지 알 수 없다는 것이다.나는 구글을 검색했지만 내가 찾은 모든 예는 이것과 같은 오래된 것이고 현재 커널 버전에는 더 이상 유효하지 않다.이 SO 질문도 살펴봤지만 여기 샘플은 소켓 작동을 위해 libnl을 사용하지만 표준 소켓 기능을 고수하고 싶다(에 의해 정의됨).sys/socket.h
그래서 어떤 플즈(plz)가 어떤 튜토리얼이나 가이드 또는 네트링크의 인터페이스와 사용법을 이해하는데 도움이 될 수 있는 어떤 것을 나에게 안내해 줄 수 있다.나는 사용자 프로그램의 소켓에서 커널의 소켓으로 연결을 설정한 다음 사용자 프로세스에서 커널로 데이터를 전송하고 커널에서 다시 수신하는 방법에 대한 아주 기본적인 예에 불과한 작업 예시를 높이 평가한다.
또한 커널 코드를 보라고 말하지 말아줘.나는 이미 하고 있지만 시간이 많이 걸리고 많이 남아있지 않아.
업데이트: 많은 시행착오 후 사용자 프로그램에서 커널로 메시지를 보내고 커널에서 사용자 프로그램으로 메시지를 보내는 다음 코드가 있음. 즉,netlink_unicast()
작동하지 않는다.작동이 안 될 뿐만 아니라 호출이 시스템을 중단시키고 나서 기계를 다시 시작해야 해.누가 한번 보고 내가 뭘 잘못하고 있는지 말해줄 수 있을까?그netlink_unicast()
호출은 다음 코드에 설명되어 있다.커널-사용자 프로그램 메시지에 대해 미결합을 해야 한다.
사용자 프로그램
#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);
}
커널 코드
#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);
커널 소스를 읽은 후에 나는 마침내 네트링크 소켓이 나를 위해 작동하도록 하는 데 성공했다.아래는 넷링크 소켓 기본사항의 예로서, 즉 넷링크 소켓의 열기, 읽고 쓰는 것, 그리고 닫는 것 등이다.
커널 모듈
#include <linux/module.h>
#include <net/sock.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;
struct sk_buff *skb_out;
int msg_size;
char *msg = "Hello from kernel";
int res;
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
msg_size = strlen(msg);
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 */
skb_out = nlmsg_new(msg_size, 0);
if (!skb_out) {
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
strncpy(nlmsg_data(nlh), msg, msg_size);
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res < 0)
printk(KERN_INFO "Error while sending bak to user\n");
}
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);
struct netlink_kernel_cfg cfg = {
.input = hello_nl_recv_msg,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
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);
MODULE_LICENSE("GPL");
사용자 프로그램
#include <linux/netlink.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.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;
int 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 */
bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_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);
}
마법 상수에 대한 관련 스레드NETLINK_USER 31
: 커널스페이스에 32개 이상의 넷링크 소켓을 가질 수 있는가?
컴파일 방법을 모르는 사람이 있을 경우 "커널 모듈 컴파일 및 로드 방법"을 검색하십시오.
http://www.cyberciti.biz/tips/compiling-linux-kernel-module.html을 참조하십시오.
http://kernel.org에 대해 모듈을 컴파일할 커널 소스 코드를 가져오십시오.
또는 원하는 커널을 실행하는 경우 머리글을 업데이트하십시오.
# apt-get install kernel-headers-$(uname -r)
예를 들어, makefile 만들기
obj-m = hello.o
KVERSION = $(shell uname -r)
all:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
만들면 많은 파일들을 얻을 수 있을 것이다.*.ko는 당신이 당신의 커널에 로딩할 사람이고, 실행한다.
# insmod hello.ko
로드된 모든 모듈을 점검하기 위해 smodd를 사용한다면, 당신의 모듈을 찾을 수 있을 것이며, 아마도 당신은 다음을 볼 것이다.
hello 12575 0
이 경우 사용자 코드를 컴파일하고 실행하십시오.
gcc hello.c -o hello.o
./hello.o
모든 것이 정상이라면 binW의 코드를 사용하여 다음과 같은 메시지를 받게 될 것이다.
Sending message to kernel
Waiting for message from kernel
Received message payload: Hello from kernel
마지막으로 다음을 사용하여 모듈을 탈거하십시오.
# rmmod hello
그것은 커널 3.2와 함께 나에게 효과가 있다.커널 3.6 이상에 대해서는 조금 변화가 필요하다.netlink_kernel_create
기능을 발휘하다
struct netlink_kernel_cfg cfg = {
.groups = 1,
.input = hello_nl_recv_msg,
};
printk("Entering: %s\n", __FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
client_side 코드에 다음 헤더 파일을 포함해야 함:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
'IT이야기' 카테고리의 다른 글
긴 형식의 인쇄물에 대한 인수는 무엇인가? (0) | 2022.05.07 |
---|---|
Vuex 스토어에서 i18n-nuxt $t 사용 (0) | 2022.05.07 |
루프 조건에서 사용할 경우 strlen이 여러 번 계산되는가? (0) | 2022.05.07 |
Vue JS(router.BeforeEach) 예외를 문자열로 변환하지 못함 (0) | 2022.05.06 |
TypeScript를 사용하여 vuex에서 커밋에 대한 유형 체킹을 추가하는 방법 (0) | 2022.05.06 |