程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> netfilter內核態與用戶態 通信 之 sockopt

netfilter內核態與用戶態 通信 之 sockopt

編輯:C++入門知識

用戶態與內核態交互通信的方法不止一種,sockopt是比較方便的一個,寫法也簡單. 缺點就是使用 copy_from_user()/copy_to_user()完成內核和用戶的通信, 效率其實不高, 多用在傳遞控制 選項 信息,不適合做大量的數據傳輸   用戶態函數: 發送:int setsockopt ( int sockfd, int proto, int cmd, void *data, int datelen); 接收:int getsockopt(int sockfd, int proto, int cmd, void *data, int datalen) 第一個參數是socket描述符; 第二個參數proto是sock協議,IP RAW的就用SOL_SOCKET/SOL_IP等,TCP/UDP socket的可用SOL_SOCKET/SOL_IP/SOL_TCP/SOL_UDP等,即高層的socket是都可以使用低層socket的命令字 的,IPPROTO_IP; 第三個參數cmd是操作命令字,由自己定義; 第四個參數是數據緩沖區起始位置指針,set操作時是將緩沖區數據寫入內核,get的時候是將內核中的數 據讀入該緩沖區; 第五個參數數據長度   內核態函數 注冊:nf_register_sockopt(struct nf_sockopt_ops *sockops) 解除:nf_unregister_sockopt(struct nf_sockopt_ops *sockops)   結構體 nf_sockopt_ops test_sockops  [cpp]   static struct nf_sockopt_ops nso = {    .pf  = PF_INET,       // 協議族    .set_optmin = 常數,    // 定義最小set命令字    .set_optmax = 常數+N,  // 定義最大set命令字    .set  = recv_msg,   // 定義set處理函數    .get_optmin = 常數,    // 定義最小get命令字    .get_optmax = 常數+N,  // 定義最大get命令字    .get  = send_msg,   // 定義set處理函數   };       其中命令字不能和內核已有的重復,宜大不宜小。命令字很重要,是用來做標識符的。而且用戶態和內核態要定義的相同, [cpp]   #define SOCKET_OPS_BASE          128   #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)   #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)   #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)     set/get處理函數是直接由用戶空間的 set/getsockopt函數調用的。 setsockopt函數向內核寫數據,用getsockopt向內核讀數據。www.2cto.com 另外set和get的處理函數的參數應該是這樣的 int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len) int send_msg(struct sock *sk, int cmd, void __user *user, unsigned int *len) 附上我修改網友的程序 內核態的module.c [cpp]   #include <linux/module.h>   #include <linux/kernel.h>   #include <linux/types.h>   #include <linux/string.h>   #include <linux/netfilter_ipv4.h>   #include <linux/init.h>   #include <asm/uaccess.h>       #define SOCKET_OPS_BASE          128   #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)   #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)   #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)      #define KMSG          "--------kernel---------"   #define KMSG_LEN      sizeof("--------kernel---------")      MODULE_LICENSE("GPL");   MODULE_AUTHOR("SiasJack");/*作者*/   MODULE_DESCRIPTION("sockopt module,simple module");//描述   MODULE_VERSION("1.0");//版本號      static int recv_msg(struct sock *sk, int cmd, void __user *user, unsigned int len)   {       int ret = 0;       printk(KERN_INFO "sockopt: recv_msg()\n");           if (cmd == SOCKET_OPS_SET)       {              char umsg[64];           int len = sizeof(char)*64;           memset(umsg, 0, len);           ret = copy_from_user(umsg, user, len);           printk("recv_msg: umsg = %s. ret = %d\n", umsg, ret);           }          return 0;   }       static int send_msg(struct sock *sk, int cmd, void __user *user, int *len)   {       int ret = 0;       printk(KERN_INFO "sockopt: send_msg()\n");        if (cmd == SOCKET_OPS_GET)       {              ret = copy_to_user(user, KMSG, KMSG_LEN);           printk("send_msg: umsg = %s. ret = %d. success\n", KMSG, ret);       }          return 0;      }      static struct nf_sockopt_ops test_sockops =   {       .pf = PF_INET,       .set_optmin = SOCKET_OPS_SET,       .set_optmax = SOCKET_OPS_MAX,       .set = recv_msg,       .get_optmin = SOCKET_OPS_GET,       .get_optmax = SOCKET_OPS_MAX,       .get = send_msg,       .owner = THIS_MODULE,   };      static int __init init_sockopt(void)   {       printk(KERN_INFO "sockopt: init_sockopt()\n");       return nf_register_sockopt(&test_sockops);   }      static void __exit exit_sockopt(void)   {       printk(KERN_INFO "sockopt: fini_sockopt()\n");       nf_unregister_sockopt(&test_sockops);   }      module_init(init_sockopt);   module_exit(exit_sockopt);     用戶態的user.c   [cpp]   #include <unistd.h>   #include <stdio.h>   #include <sys/socket.h>   #include <linux/in.h>   #include <string.h>   #include <errno.h>       #define SOCKET_OPS_BASE      128   #define SOCKET_OPS_SET       (SOCKET_OPS_BASE)   #define SOCKET_OPS_GET      (SOCKET_OPS_BASE)   #define SOCKET_OPS_MAX       (SOCKET_OPS_BASE + 1)       #define UMSG      "----------user------------"   #define UMSG_LEN  sizeof("----------user------------")       char kmsg[64];       int main(void)   {       int sockfd;       int len;       int ret;           sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);       if(sockfd < 0)       {              printf("can not create a socket\n");           return -1;        }             /*call function recv_msg()*/       ret = setsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_SET, UMSG, UMSG_LEN);       printf("setsockopt: ret = %d. msg = %s\n", ret, UMSG);       len = sizeof(char)*64;           /*call function send_msg()*/       ret = getsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_GET, kmsg, &len);       printf("getsockopt: ret = %d. msg = %s\n", ret, kmsg);       if (ret != 0)       {              printf("getsockopt error: errno = %d, errstr = %s\n", errno, strerror(errno));       }             close(sockfd);       return 0;   }     Makefile----系統不同命令可能不同,我的fedora 12 [cpp]   TARGET = socketopt   OBJS = module.o   MDIR = drivers/misc      EXTRA_CFLAGS = -DEXPORT_SYMTAB   CURRENT = $(shell uname -r)   KDIR = /lib/modules/$(CURRENT)/build   PWD = $(shell pwd)   DEST = /lib/modules/$(CURRENT)/kernel/$(MDIR)      obj-m := $(TARGET).o      $(TARGET)-objs :=$(OBJS)      default:       make -C  $(KDIR) SUBDIRS=$(PWD) modules        gcc -o user user.c   $(TARGET).o: $(OBJS)       $(LD) $(LD_RFLAG) -r -o $@ $(OBJS)      insmod:       insmod $(TARGET).ko   rmmod:       rmmod $(TARGET).ko      clean:       -rm -rf *.o *.ko .$(TARGET).ko.cmd .*.flags *.mod.c modules.order  Module.symvers .tmp_versions       -rm -rf protocol/*.o protocol/.*.o.cmd *.markers        -rm -rf user   -include $(KDIR)/Rules.make     運行的結果 [cpp]   [root@root socket]# make   //編譯   make -C  /lib/modules/2.6.31.5-127.fc12.i686.PAE/build SUBDIRS=/root/study/c_study/socket modules    make[1]: Entering directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE'     CC [M]  /root/study/c_study/socket/module.o     LD [M]  /root/study/c_study/socket/socketopt.o     Building modules, stage 2.     MODPOST 1 modules     CC      /root/study/c_study/socket/socketopt.mod.o     LD [M]  /root/study/c_study/socket/socketopt.ko   make[1]: Leaving directory `/usr/src/kernels/2.6.31.5-127.fc12.i686.PAE'   gcc -o user user.c   [root@root socket]#    [root@root socket]# make insmod   //加載   insmod socketopt.ko   [root@root socket]#    [root@root socket]# lsmod    //查看加載成功   Module                  Size  Used by   socketopt               1968  0    sunrpc                158388  1    [root@root socket]# dmesg -c  //清楚以前的系統信息   [root@root socket]# ./user  //運行用戶態   setsockopt: ret = 0. msg = ----------user------------   getsockopt: ret = 0. msg = --------kernel---------   [root@root socket]# dmesg  //查看最新生成的日志   sockopt: recv_msg()   recv_msg: umsg = ----------user------------. ret = 0   sockopt: send_msg()   send_msg: umsg = --------kernel---------. ret = 0. success      

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved