netfilter内核态与用户态 通信 之 sockopt
用户态与内核态交互通信的方法不止一种,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
struct nf_sockopt_ops {
struct list_head list;
u_int8_t pf; // 协议族
/* Non-inclusive ranges: use 0/0/NULL to never get called. */
int set_optmin;// 定义最小set命令字
int set_optmax;// 定义最大set命令字
int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);// 定义set处理函数
#ifdef CONFIG_COMPAT
int (*compat_set)(struct sock *sk, int optval,
void __user *user, unsigned int len);
#endif
int get_optmin;// 定义最小get命令字
int get_optmax;// 定义最大get命令字
int (*get)(struct sock *sk, int optval, void __user *user, int *len);// 定义get处理函数
#ifdef CONFIG_COMPAT
int (*compat_get)(struct sock *sk, int optval,
void __user *user, int *len);
#endif
/* Use the module struct to lock set/get code in place */
struct module *owner;
};
其中命令字不能和内核已有的重复,宜大不宜小。命令字很重要,是用来做标识符的。而且用户态和内核态要定义的相同,
系统调用如下:sockt==》sock_common_setsockopt==》sk->sk_prot->setsockopt==》ip_setsockopt(tcp为例)
==>do_ip_setsockopt
==> nf_setsockopt==>nf_sockopt
int ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, unsigned int optlen)
{
int err; if (level != SOL_IP)
return -ENOPROTOOPT; err = do_ip_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY &&
optname != IP_XFRM_POLICY &&
!ip_mroute_opt(optname)) {
lock_sock(sk);
err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
release_sock(sk);
}
#endif
return err;
} /* Call get/setsockopt() */
static int nf_sockopt(struct sock *sk, u_int8_t pf, int val,
char __user *opt, int *len, int get)
{
struct nf_sockopt_ops *ops;
int ret; ops = nf_sockopt_find(sk, pf, val, get);
if (IS_ERR(ops))
return PTR_ERR(ops); if (get)
ret = ops->get(sk, val, opt, len);
else
ret = ops->set(sk, val, opt, *len); module_put(ops->owner);
return ret;
} int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
unsigned int len)
{
return nf_sockopt(sk, pf, val, opt, &len, 0);
}

#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);
#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;
}
https://blog.csdn.net/jk110333/article/details/8642261 来自转载
netfilter内核态与用户态 通信 之 sockopt的更多相关文章
- Linux 内核态与用户态通信 netlink
参考资料: https://blog.csdn.net/zqixiao_09/article/details/77131283 https://www.cnblogs.com/lopnor/p/615 ...
- 在linux系统中实现各项监控的关键技术(2)--内核态与用户态进程之间的通信netlink
Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 ...
- linux内核态和用户态的信号量
在Linux的内核态和用户态都有信号量,使用也不同,简单记录一下. 1> 内核信号量,由内核控制路径使用.内核信号量是struct semaphore类型的对象,它在中定义struct sema ...
- Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
一.现代操作系统的权限分离: 现代操作系统一般都至少分为内核态和用户态.一般应用程序通常运行于用户态,而当应用程序调用系统调用时候会执行内核代码,此时会处于内核态.一般的,应用程序是不能随便进入内核态 ...
- 操作系统基本概念(内核态与用户态、操作系统结构)-by sixleaves
内核态与用户态(为什么存在这种机制.程序应处于哪个状态.如何判断当前所处状态.哪些功能需要内核态.如何实现这种机制) 1.首先我们应该思考清楚为什么会有内核态和用户态?(为什么存在这种机制) 因为计算 ...
- go语言学习--内核态和用户态(协程)
go中的一个特点就是引入了相比于线程更加轻量级的协程(用户态的线程),那么什么是用户态和内核态呢? 一.什么是用户态和内核态 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核 ...
- Linux内核态和用户态
两张图说明Linux内核态和用户态之间的关系
- [OS] 内核态和用户态的区别
http://blog.csdn.net/fatsandwich/article/details/2131707# http://jakielong.iteye.com/blog/771663 当一个 ...
- cpu与寄存器,内核态与用户态及如何切换
cpu:相当于计算机的大脑负责运算和发送命令: 寄存器:寄存器是cpu当中的一个有限存储部件,cpu从内存调用数据时,寄存器会将从内存调用的数据进行更新在寄存器中以一个字或变量进行存储. 寄存器总共分 ...
- 【转】linux内核态和用户态的区别
原文网址:http://www.mike.org.cn/articles/linux-kernel-mode-and-user-mode-distinction/ 内核态与用户态是操作系统的两种运行级 ...
随机推荐
- Javascript判断数据类型的五种方式及其特殊性
Javascript判断数据类型的五种方式及区别 @ 目录 typeof instanceof Object.prototype.toString isArray iisNaN ----------- ...
- spring-boot-route(十六)使用logback生产日志文件
日志是一个系统非常重要的一部分,我们经常需要通过查看日志来定位问题,今天我们一起来学习一下Spring Boot的日志系统.有很多同学习惯性的在生产代码中使用System.out来输出日志,这是不推荐 ...
- .net c#后台请求接口
我们在请求接口的时候,有时因为跨域的问题,总是请求接口失败,亦或是请求接口时,页面还存在跳转的问题,这个时候,我们通过前台ajax请求自己的一般处理程序,用一般处理程序请求客户提供的接口 //获取to ...
- 智能指针(1)-std::unique_ptr
std::unique_ptr std::unique_ptr是一种几乎和原始指针一样高效的智能指针,对所管理的指针资源拥有独占权.由C++11标准引入,用于替代C++98中过时的std::auto_ ...
- Linux系统编程—信号捕捉
前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式: 忽略: 捕捉. 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作.下面详细介绍两个信 ...
- laravel设置excel高度
<?php use App\Services\UploadService; use Maatwebsite\Excel\Facades\Excel; class ExcelTest extend ...
- Cypress系列(68)- request() 命令详解
如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 作用 发起一个 HTTP 请求 语法格式 ...
- python提取视频第一帧图片
一.实现代码 # -*- coding: utf-8 -*- import cv2 from PIL import Image from io import BytesIO def tryTime(m ...
- nginx tp5配置
location ~ [^/]\.php(/|$) { #fastcgi_pass remote_php_ip:9000; fastcgi_pass unix:/dev/shm/php-cgi.soc ...
- Error response from daemon: conflict: unable to delete a2f2e369e78e (cannot be forced) - image has dependent child images
错误现象: Error response from daemon: conflict: unable to delete a2f2e369e78e (cannot be forced) - image ...