歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 通過netlink實現內核模塊和應用層通信

通過netlink實現內核模塊和應用層通信

日期:2017/3/1 11:09:04   编辑:Linux編程

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

內核模塊代碼:

  1. /*
  2. * author: [email protected]
  3. * date : 2011-10-29
  4. */
  5. #include <linux/module.h>
  6. #include <linux/netlink.h>
  7. #include <linux/sched.h>
  8. #include <net/sock.h>
  9. #include <linux/proc_fs.h>
  10. #include <linux/netfilter.h>
  11. #include <linux/netfilter_ipv4.h>
  12. #include <linux/ip.h>
  13. #include <linux/tcp.h>
  14. #include <linux/icmp.h>
  15. #include <linux/udp.h>
  16. #define NETLINK_TEST 30
  17. /* 調試信息 */
  18. #define LOGMSG(fmt, arg...) \
  19. do{ \
  20. printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \
  21. }while(0)
  22. /* 錯誤信息 */
  23. #define LOGERR(fmt, arg...) \
  24. do{ \
  25. printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \
  26. }while(0)
  27. /* 斷言 */
  28. #define ASSERT(expr) \
  29. if (unlikely(!(expr))) { \
  30. printk("Assertion failed! %s,%s,%s,line=%d\n", \
  31. #expr, __FILE__, __func__, __LINE__); \
  32. }
  33. /* 消息最大值 */
  34. #define MAX_MSG_LEN 1024
  35. enum{
  36. NLMSG_TYPE_NONE = 0,
  37. NLMSG_TYPE_SETPID, /* 設置PID */
  38. NLMSG_TYPE_KERNEL, /* 消息來自內核 */
  39. NLMSG_TYPE_APP, /* 消息來自應用層 */
  40. };
  41. struct nlmsg{
  42. int type; /* 消息類型 */
  43. int len; /* 消息長度,包括頭部 */
  44. char msg[MAX_MSG_LEN]; /* 消息正文 */
  45. };
  46. /* netlink socket */
  47. static struct sock *g_nl_sk = NULL;
  48. static int g_nlpid = -1; /* 應用層接收程序PID */
  49. /*
  50. * 發送整個從ip頭開始的skb數據到應用層
  51. *
  52. * param[in]: sk, skb發送目的socket
  53. * param[in]: skb, 待發送的skb
  54. * return -1, 失敗; 0, 成功
  55. * */
  56. int nl_sendskb(struct sock *sk, struct sk_buff *skb)
  57. {
  58. struct iphdr *iph = NULL;
  59. struct nlmsghdr *nlh = NULL;
  60. struct sk_buff *nl_skb = NULL;
  61. int skb_len = 0;
  62. ASSERT(skb != NULL);
  63. ASSERT(sk != NULL);
  64. if(g_nlpid < 0)
  65. return 0;
  66. iph = ip_hdr(skb);
  67. skb_len = iph->tot_len;
  68. /* NLMSG_SPACE: sizeof(struct nlmsghdr) + len按4字節對齊 */
  69. nl_skb = alloc_skb(NLMSG_SPACE(skb_len), GFP_ATOMIC);
  70. if(!nl_skb)
  71. {
  72. LOGERR("nl_skb == NULL, failed!\n");
  73. return -1;
  74. }
  75. /*
  76. * static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
  77. * int type, int payload, int flags);
  78. * 設置skb->tail指針指向skb->data + sizeof(struct nlmsghdr) + payload
  79. * skb->len = sizeof(struct nlmsghdr) + payload
  80. */
  81. nlh = nlmsg_put(nl_skb, 0, 0, 0, NLMSG_SPACE(skb_len) - sizeof(struct nlmsghdr), 0);
  82. NETLINK_CB(nl_skb).pid = 0; /* 0代表數據來自內核 */
  83. memcpy(NLMSG_DATA(nlh), (char *)iph, htons(iph->tot_len));
  84. /* 將數據發送給進程號22345的進程 */
  85. return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);
  86. }
  87. /*
  88. * 發送字符串到應用層
  89. *
  90. * param[in]: sk, 數據發往的socket
  91. * param[in]: pmsg, 待發送字符串
  92. * param[in]: msglen, 待發送字符串長度
  93. *
  94. * return: -1, 失敗; 0, 成功
  95. * */
  96. int nl_sendmsg(struct sock *sk, struct nlmsg *pmsg)
  97. {
  98. struct nlmsghdr *nlh = NULL;
  99. struct sk_buff *nl_skb = NULL;
  100. int msglen = pmsg->len;
  101. ASSERT(pmsg != NULL);
  102. ASSERT(sk != NULL);
  103. if(g_nlpid < 0)
  104. return 0;
  105. nl_skb = alloc_skb(NLMSG_SPACE(msglen), GFP_ATOMIC);
  106. if(!nl_skb)
  107. {
  108. LOGERR("nl_skb == NULL, msglen = %d, failed!\n", msglen);
  109. return -1;
  110. }
  111. nlh = nlmsg_put(nl_skb, 0, 0, 0,
  112. NLMSG_SPACE(msglen) - NLMSG_HDRLEN, 0);
  113. NETLINK_CB(nl_skb).pid = 0;
  114. memcpy(NLMSG_DATA(nlh), pmsg, msglen);
  115. return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);
  116. }
  117. /*
  118. * 從應用層接收數據, netlink_kernel_create注冊的回調
  119. * param[in]: skb, 包含netlink數據的skb
  120. *
  121. * skb常用操作函數
  122. * skb_put : skb->tail += len, skb->len += len
  123. * skb_pull: skb->data += len, skb->len -= len
  124. * skb_push: skb->data -= len, skb->len += len
  125. */
  126. static void nl_recvmsg(struct sk_buff *skb)
  127. {
  128. struct nlmsg *pmsg = NULL;
  129. struct nlmsghdr *nlh = NULL;
  130. uint32_t rlen = 0;
  131. while(skb->len >= NLMSG_SPACE(0))
  132. {
  133. nlh = nlmsg_hdr(skb);
  134. if(nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
  135. return;
  136. rlen = NLMSG_ALIGN(nlh->nlmsg_len);
  137. if(rlen > skb->len)
  138. rlen = skb->len;
  139. pmsg = (struct nlmsg*)NLMSG_DATA(nlh);
  140. switch(pmsg->type)
  141. {
  142. case NLMSG_TYPE_SETPID:
  143. g_nlpid = nlh->nlmsg_pid;
  144. LOGMSG("pid: %d\n", g_nlpid);
  145. LOGMSG("msg: %s\n", pmsg->msg);
  146. break;
  147. case NLMSG_TYPE_KERNEL:
  148. break;
  149. case NLMSG_TYPE_APP:
  150. break;
  151. }
  152. /* 獲取下一條netlink消息 */
  153. skb_pull(skb, rlen);
  154. }
  155. }
  156. /*
  157. * netfilter PRE_ROUTING鉤子
  158. * */
  159. unsigned int pre_routing_hook(unsigned int hooknum,
  160. struct sk_buff *skb,
  161. const struct net_device *in,
  162. const struct net_device *out,
  163. int (*okfn)(struct sk_buff *))
  164. {
  165. char *psend = "msg for kernel";
  166. struct nlmsg msg;
  167. int ret = 0;
  168. msg.type = NLMSG_TYPE_KERNEL;
  169. msg.len = strlen(psend) + offsetof(struct nlmsg, msg) + 1;
  170. memcpy(msg.msg, psend, msg.len);
  171. //ret = nl_sendskb(g_nl_sk, skb);
  172. ret = nl_sendmsg(g_nl_sk, &msg);
  173. //LOGMSG("ok\n");
  174. return NF_ACCEPT;
  175. }
  176. static struct nf_hook_ops local_in_ops __read_mostly = {
  177. .hook = pre_routing_hook,
  178. .owner = THIS_MODULE,
  179. .pf = PF_INET,
  180. .hooknum = NF_INET_PRE_ROUTING,
  181. .priority = NF_IP_PRI_FIRST
  182. };
  183. static int __init nl_init(void)
  184. {
  185. int ret = 0;
  186. /*
  187. * struct sock *netlink_kernel_create(struct net *net, int unit, unsigned int groups,
  188. * void (*input)(struct sk_buff *skb),
  189. * struct mutex *cb_mutex, struct module *module)
  190. */
  191. g_nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_recvmsg, NULL, THIS_MODULE);
  192. if (!g_nl_sk) {
  193. LOGERR("Fail to create netlink socket.\n");
  194. return -1;
  195. }
  196. ret = nf_register_hook(&local_in_ops);
  197. if(ret < 0)
  198. {
  199. LOGMSG("nf_register_hook failed!\n");
  200. goto sock_release;
  201. }
  202. LOGMSG("ok!\n");
  203. return 0;
  204. sock_release:
  205. if(g_nl_sk)
  206. sock_release(g_nl_sk->sk_socket);
  207. return -1;
  208. }
  209. static void __exit nl_exit(void)
  210. {
  211. synchronize_sched();
  212. if(g_nl_sk)
  213. sock_release(g_nl_sk->sk_socket);
  214. nf_unregister_hook(&local_in_ops);
  215. LOGMSG("ok!\n");
  216. }
  217. module_init(nl_init);
  218. module_exit(nl_exit);
  219. MODULE_LICENSE("GPL");
  220. MODULE_AUTHOR("[email protected]");
Copyright © Linux教程網 All Rights Reserved