linux netlink 编程示例(二)应用层
程序员文章站
2024-03-23 13:20:52
...
这篇文章给出一个netlink应用层程序用例,和上一篇博客内核篇结合起来参考。
内核版本:3.4.39
nlclient.c
/*
* Description : 应用层netlink编程
* Date :20180529
* Author :mason
* Mail : aaa@qq.com
*
*/
#include <linux/netlink.h>
#include <linux/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "nlclient.h"
void main() {
int nlfd;
int *value;
int opt, arg;
unsigned int len;
struct iovec iov[1];
struct msghdr msg;
struct sockaddr_nl src, dst;
struct nlmsghdr *nlh, *nlh1, *nlh2 = NULL;
// 创建netlink套接字
nlfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_TEST_MODULE);
if (nlfd == -1) {
log("create netlink socket fail\n");
return;
}
memset(&src, 0, sizeof(struct sockaddr_nl));
memset(&dst, 0, sizeof(struct sockaddr_nl));
memset(&msg, 0, sizeof(struct msghdr));
// 设置本地地址
src.nl_family = AF_NETLINK;
src.nl_pid = getpid();
src.nl_groups = 0;
// 设置内核netlink地址
dst.nl_family = AF_NETLINK;
dst.nl_pid = 0;
dst.nl_groups = 0;
// 绑定本地地址
bind(nlfd, (struct sockaddr*)&src, sizeof(struct sockaddr_nl));
// 申请netlink消息头域
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(int));
while(1) {
log("input option :\n"
"1 : set \n"
"2 : get \n"
"default : quit\n");
scanf("%d", &opt);
switch (opt) {
// set
case 1 :
log("input value to set:");
scanf("%d", &arg);
memset(nlh, 0, NLMSG_SPACE(sizeof(int)));
nlh->nlmsg_len = NLMSG_SPACE(sizeof(int));
// 设置netlink 应用层的pid
nlh->nlmsg_pid = getpid();
// 设置消息类型
nlh->nlmsg_type = NLKERNEL_SET;
// 设置标志位
nlh->nlmsg_flags = NLM_F_REQUEST;
// 填充发送消息结构体
iov[0].iov_base = (void *)nlh;
iov[0].iov_len = nlh->nlmsg_len;
value = (int *)NLMSG_DATA(nlh);
*value = arg;
msg.msg_name = (void *)&dst;
msg.msg_namelen = sizeof(struct sockaddr_nl);
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
// 发送netlink 消息给内核
sendmsg(nlfd, &msg, 0);
log("send set msg to kernel success \n\n");
break;
// get
case 2 :
memset(nlh, 0, NLMSG_SPACE(int));
nlh->nlmsg_len = NLMSG_SPACE(int);
nlh->nlmsg_pid = getpid();
// 设置netlink消息类型
nlh->nlmsg_type = NLKERNEL_GET;
nlh->nlmsg_flags = NLM_F_REQUEST;
iov[0].iov_base = (void *)nlh;
iov[0].iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dst;
msg.msg_namelen = sizeof(struct sockaddr_nl);
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
// 发送消息
log("send get msg to kernel success \n");
sendmsg(nlfd, &msg, 0);
memset(nlh, 0, NLMSG_SPACE(sizeof(int)));
nlh->nlmsg_len = NLMSG_SPACE(sizeof(int));
iov[0].iov_base = (void *)nlh;
iov[0].iov_len = nlh->nlmsg_len;
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
// 接收netlink内核端消息
len = recvmsg(nlfd, &msg, 0);
value = (int *)NLMSG_DATA(nlh);
log("kernel return : %d \r\n\n", *value);
break;
default :
goto end;
}
}
end:
close(nlfd);
if (nlh)
free(nlh);
return ;
}
nlclient.h
#ifndef _NLCLIENT_H
#define _NLCLIENT_H
#define log(fmt,arg...) \
printf("[nlclient] "fmt,##arg)
#define NETLINK_TEST_MODULE 17 /* 抓包 netlink 协议 */
typedef enum netlink_msg_type {
NLKERNEL_GET = NLMSG_MIN_TYPE +1, /* value : 17 */
NLKERNEL_SET, /* value : 18 */
NLKERNEL_END,
}NETLINK_MSG_TYPE;
#endif
Makefile
nlclient:
$(CC) -o nlclient nlclient.c
clean:
@rm -rf *.o nlclient
代码可以在github上 clone下来运行
aaa@qq.com:FuYuanDe/nlnetlink.git
编译完成后先运行netlink内核端再运行应用层程序,否则会出现创建netlink套接字失败问题。
运行截图如下:
应用层:分别执行了get, set, get 操作,通过netlink与内核通信
内核端:
相比其它的用户空间与内核空间通信方式,netlink的交互性非常好。此外在实际应用的时候要注意字节对齐问题。