通过netlink实现内核模块和应用层通信
来源:互联网 发布:开淘宝网店的流程2017 编辑:程序博客网 时间:2024/05/22 00:30
贴上代码,方便以后查阅。
skb常用操作函数,比较容易弄混
skb_put : skb->tail += len, skb->len += len
skb_pull: skb->data += len, skb->len -= len
skb_push: skb->data -= len, skb->len += len
内核版本linux2.6.38,编译环境gcc 4.4.4,centos6.0
内核模块代码:
/* * author: hoi0714@163.com * date : 2011-10-29 */#include <linux/module.h>#include <linux/netlink.h>#include <linux/sched.h>#include <net/sock.h>#include <linux/proc_fs.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/icmp.h>#include <linux/udp.h>#define NETLINK_TEST 30/* 调试信息 */#define LOGMSG(fmt, arg...) \do{ \ printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \}while(0)/* 错误信息 */#define LOGERR(fmt, arg...) \do{ \ printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \}while(0)/* 断言 */#define ASSERT(expr) \if (unlikely(!(expr))) { \ printk("Assertion failed! %s,%s,%s,line=%d\n", \ #expr, __FILE__, __func__, __LINE__); \}/* 消息最大值 */#define MAX_MSG_LEN 1024enum{ NLMSG_TYPE_NONE = 0, NLMSG_TYPE_SETPID, /* 设置PID */ NLMSG_TYPE_KERNEL, /* 消息来自内核 */ NLMSG_TYPE_APP, /* 消息来自应用层 */};struct nlmsg{ int type; /* 消息类型 */ int len; /* 消息长度,包括头部 */ char msg[MAX_MSG_LEN]; /* 消息正文 */};/* netlink socket */static struct sock *g_nl_sk = NULL;static int g_nlpid = -1; /* 应用层接收程序PID *//* * 发送整个从ip头开始的skb数据到应用层 * * param[in]: sk, skb发送目的socket * param[in]: skb, 待发送的skb * return -1, 失败; 0, 成功 * */int nl_sendskb(struct sock *sk, struct sk_buff *skb){ struct iphdr *iph = NULL; struct nlmsghdr *nlh = NULL; struct sk_buff *nl_skb = NULL; int skb_len = 0; ASSERT(skb != NULL); ASSERT(sk != NULL); if(g_nlpid < 0) return 0; iph = ip_hdr(skb); skb_len = iph->tot_len; /* NLMSG_SPACE: sizeof(struct nlmsghdr) + len按4字节对齐 */ nl_skb = alloc_skb(NLMSG_SPACE(skb_len), GFP_ATOMIC); if(!nl_skb) { LOGERR("nl_skb == NULL, failed!\n"); return -1; } /* * static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, * int type, int payload, int flags); * 设置skb->tail指针指向skb->data + sizeof(struct nlmsghdr) + payload * skb->len = sizeof(struct nlmsghdr) + payload */ nlh = nlmsg_put(nl_skb, 0, 0, 0, NLMSG_SPACE(skb_len) - sizeof(struct nlmsghdr), 0); NETLINK_CB(nl_skb).pid = 0; /* 0代表数据来自内核 */ memcpy(NLMSG_DATA(nlh), (char *)iph, htons(iph->tot_len)); /* 将数据发送给进程号22345的进程 */ return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);}/* * 发送字符串到应用层 * * param[in]: sk, 数据发往的socket * param[in]: pmsg, 待发送字符串 * param[in]: msglen, 待发送字符串长度 * * return: -1, 失败; 0, 成功 * */int nl_sendmsg(struct sock *sk, struct nlmsg *pmsg){ struct nlmsghdr *nlh = NULL; struct sk_buff *nl_skb = NULL; int msglen = pmsg->len; ASSERT(pmsg != NULL); ASSERT(sk != NULL); if(g_nlpid < 0) return 0; nl_skb = alloc_skb(NLMSG_SPACE(msglen), GFP_ATOMIC); if(!nl_skb) { LOGERR("nl_skb == NULL, msglen = %d, failed!\n", msglen); return -1; } nlh = nlmsg_put(nl_skb, 0, 0, 0, NLMSG_SPACE(msglen) - NLMSG_HDRLEN, 0); NETLINK_CB(nl_skb).pid = 0; memcpy(NLMSG_DATA(nlh), pmsg, msglen); return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);}/* * 从应用层接收数据, netlink_kernel_create注册的回调 * param[in]: skb, 包含netlink数据的skb * * skb常用操作函数 * skb_put : skb->tail += len, skb->len += len * skb_pull: skb->data += len, skb->len -= len * skb_push: skb->data -= len, skb->len += len */static void nl_recvmsg(struct sk_buff *skb){ struct nlmsg *pmsg = NULL; struct nlmsghdr *nlh = NULL; uint32_t rlen = 0; while(skb->len >= NLMSG_SPACE(0)) { nlh = nlmsg_hdr(skb); if(nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; rlen = NLMSG_ALIGN(nlh->nlmsg_len); if(rlen > skb->len) rlen = skb->len; pmsg = (struct nlmsg*)NLMSG_DATA(nlh); switch(pmsg->type) { case NLMSG_TYPE_SETPID: g_nlpid = nlh->nlmsg_pid; LOGMSG("pid: %d\n", g_nlpid); LOGMSG("msg: %s\n", pmsg->msg); break; case NLMSG_TYPE_KERNEL: break; case NLMSG_TYPE_APP: break; } /* 获取下一条netlink消息 */ skb_pull(skb, rlen); }}/* * netfilter PRE_ROUTING钩子 * */unsigned int pre_routing_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ char *psend = "msg for kernel"; struct nlmsg msg; int ret = 0; msg.type = NLMSG_TYPE_KERNEL; msg.len = strlen(psend) + offsetof(struct nlmsg, msg) + 1; memcpy(msg.msg, psend, msg.len); //ret = nl_sendskb(g_nl_sk, skb); ret = nl_sendmsg(g_nl_sk, &msg); //LOGMSG("ok\n"); return NF_ACCEPT;}static struct nf_hook_ops local_in_ops __read_mostly = { .hook = pre_routing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_FIRST};static int __init nl_init(void){ int ret = 0; /* * struct sock *netlink_kernel_create(struct net *net, int unit, unsigned int groups, * void (*input)(struct sk_buff *skb), * struct mutex *cb_mutex, struct module *module) */ g_nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_recvmsg, NULL, THIS_MODULE); if (!g_nl_sk) { LOGERR("Fail to create netlink socket.\n"); return -1; } ret = nf_register_hook(&local_in_ops); if(ret < 0) { LOGMSG("nf_register_hook failed!\n"); goto sock_release; } LOGMSG("ok!\n"); return 0;sock_release: if(g_nl_sk) sock_release(g_nl_sk->sk_socket); return -1;}static void __exit nl_exit(void){ synchronize_sched(); if(g_nl_sk) sock_release(g_nl_sk->sk_socket); nf_unregister_hook(&local_in_ops); LOGMSG("ok!\n");}module_init(nl_init);module_exit(nl_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("hoi0714@163.com");
内核模块Makefile
module := netlinkobj-m := $(module).o#$(module)-objs := $(module).oKDIR=/root/kernel_newKHDR=/root/kernel_new/includeEXTRA_CFLAGS += $(FLAG) -I$(KHDR) -O2 -D__KERNEL__ -DMODULE $(INCLUDE) -DEXPORT_SYMTABCPPFLAGS += $(FLAG) -I$(KHDR)OUTDIR =TARGET = netlink.koTARGETDIR = /lib/modules/all:make -C $(KDIR) M=$(PWD) modulesclean:make -C $(KDIR) M=$(PWD) clean install: allinstall --verbose --mode=0755 $(OUTDIR)$(TARGET) $(INSTALLROOT)$(TARGETDIR)
/* * author: hoi0714@163.com * date : 2011-10-29 */#include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/types.h> #include <string.h> #include <asm/types.h> #include <linux/netlink.h> #include <linux/socket.h> #include <stddef.h>#include <errno.h> #define FREE_INIT(ptr) do{ \ free(ptr); \ ptr = NULL; \}while(0)/* 消息最大值 */#define MAX_MSG_LEN 1024enum{ NLMSG_TYPE_NONE = 0, NLMSG_TYPE_SETPID, /* 设置PID */ NLMSG_TYPE_KERNEL, /* 消息来自内核 */ NLMSG_TYPE_APP, /* 消息来自应用层 */};struct nlmsg{ int type; /* 消息类型 */ int len; /* 消息长度,包括头部 */ char msg[MAX_MSG_LEN]; /* 消息正文 */};#define NETLINK_TEST 30 /* * 打开netlink * return: 0, 成功; -1, 失败 * */int netlink_open(void){ struct sockaddr_nl saddr; int sockfd = -1, ret = 0; sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST); if(sockfd < -1){ perror("create socket!\n"); return -1; } memset(&saddr, 0, sizeof(saddr)); saddr.nl_family = PF_NETLINK; saddr.nl_pid = getpid(); // self pid saddr.nl_groups = 0; // multi cast ret = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); if(ret < 0){ perror("bind failed!\n"); close(sockfd); return -1; } return sockfd;}/* * 发送信息 * param[in]: sockfd * param[in]: pmsg, 待发送信息 * * return: 0, 发送成功; -1: 发送失败 * */int netlink_send(int sockfd, struct nlmsg *pmsg){ struct msghdr msg; struct iovec iov; struct nlmsghdr *nlh = NULL; int msglen = pmsg->len; int totlen = NLMSG_SPACE(pmsg->len); int ret = 0; nlh = malloc(totlen); if(!nlh) { fprintf(stderr, "malloc failed!\n"); return -1; } nlh->nlmsg_len = totlen; nlh->nlmsg_flags = 0; nlh->nlmsg_pid = getpid(); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; memcpy(NLMSG_DATA(nlh), pmsg, msglen); ret = sendmsg(sockfd, &msg, 0); if(ret < 0) { fprintf(stderr, "sendmsg failed!\n"); FREE_INIT(nlh); return -1; } return 0; }/* * 接收信息 * param[in]: sockfd * param[out]: pmsg * * return 0, 成功; -1, 失败 * */int netlink_recv(int sockfd, struct nlmsg *pmsg){ struct msghdr msg; struct iovec iov; struct nlmsghdr *nlh = NULL; int msglen = sizeof(*pmsg); int totlen = NLMSG_SPACE(sizeof(*pmsg)); int ret = 0; nlh = malloc(totlen); if(!nlh) { fprintf(stderr, "malloc failed!\n"); return -1; } iov.iov_base = (void *)nlh; iov.iov_len = totlen; memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; memcpy(NLMSG_DATA(nlh), pmsg, msglen); ret = recvmsg(sockfd, &msg, 0); if(ret < 0) { fprintf(stderr, "recvmsg failed!\n"); FREE_INIT(nlh); return -1; } memcpy(pmsg, NLMSG_DATA(nlh), msglen); return 0;}/* * 关闭netlink * param[in]: sockfd, netlink socket号 * */void netlink_close(int sockfd){ if(sockfd > 0) close(sockfd);}int main(int argc, char* argv[]) { int sockfd = -1; int ret = 0; struct nlmsg msg; char *psend = "msg from app!"; memset(&msg, 0, sizeof(msg)); /* 创建netlink socket */ sockfd = netlink_open(); if(sockfd < 0) { fprintf(stderr, "netlink_open failed!\n"); return -1; } /* 将进程号通知内核 */ msg.type = NLMSG_TYPE_SETPID; msg.len = strlen(psend) + offsetof(struct nlmsg, msg) + 1; memcpy(msg.msg, psend, strlen(psend)); ret = netlink_send(sockfd, &msg); if(ret < 0) { fprintf(stderr, "netlink_send failed!\n"); return -1; } /* 接收消息 */ while(1) { ret = netlink_recv(sockfd, &msg); if(ret < 0) { fprintf(stderr, "netlink_recv failed!\n"); return -1; } printf("msg: %s\n", msg.msg); } /* 关闭netlink */ netlink_close(sockfd); return 0; }
- 通过netlink实现内核模块和应用层通信
- 通过netlink实现内核模块和应用层通信
- 应用netlink的内核模块和应用程序Makefile编写
- 应用层和内核层通信
- netlink socket实现内核和用户的通信
- Netlink 内核实现分析(二):通信
- Netlink+内核实现分析(二):通信
- 2.6.27内核 netlink socket实现内核和用户的通信
- 基于openswan klips的IPsec VPN实现分析(四)应用层和内核通信(1)
- 基于openswan klips的IPsec VPN实现分析(五)应用层和内核通信(2)
- socket的内核和上层通信机制(netlink) -- linux内核
- IPsec 应用层和内核态通信方式
- 内核层与应用层通信详解
- Netlink实现Linux内核与用户空间通信
- Netlink实现Linux内核与用户空间通信
- Netlink实现Linux内核与用户空间通信
- Generic Netlink内核实现分析(二):通信
- Netlink实现Linux内核与用户空间通信
- 绘图Draw
- 黑马程序员_关于内部类的几个问题的综合讨论。
- 大批量文件下载
- 琐碎的java
- 在Windows .NET平台下使用Memcached
- 通过netlink实现内核模块和应用层通信
- [学习记号 - SL代码] Silverlight可拖放工具类
- 【蝴蝶效应】
- 【青蛙现象】
- Excel VBA - 数组及其他知识
- 【鳄鱼法则】
- 【鲇鱼效应】
- 【羊群效应】
- 从个体到全体-对于计数问题的一些思考