一般情况下,get/setsockopt第第三个参数和第二个参数紧密相关,即一般选定了level,optname也基本就选定了范围。但是可以原是套接字可以自定义sockopt,并且netfilter还为此提供了几个接口。使用方法如下:
首先要定义一个struct nf_sockopt_ops类型的结构体,然后通过nf_register_sockopt将其注册,最后通过 nf_sockopt_ops的get和set函数对外提供结构,供用户态使用get/setsockopt来操作。废话不多说,上代码。
内核模块代码hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/socket.h>
#include <linux/netfilter_ipv4.h>
#include <linux/string.h>
#define SOCKET_OPS_BASE128/* base for firewall socket options */
#define SOCKET_OPS_SET_HELLO(SOCKET_OPS_BASE + 0)
#define SOCKET_OPS_SET_WORLD(SOCKET_OPS_BASE + 1)
#define SOCKET_OPS_GET_HELLO(SOCKET_OPS_BASE + 0)
#define SOCKET_OPS_GET_WORLD(SOCKET_OPS_BASE + 1)
// If SOCKET_OPS_BASE+1, ERROR
#define SOCKET_OPS_MAX(SOCKET_OPS_BASE + 2)
static inthello= 0;
static charworld[16]= {'\0'};
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LGW");
MODULE_DESCRIPTION("LGW Kernel Module");
static int set_var(struct sock *sk, int cmd, void __user *user, unsigned int len)
{
int ret = 0;
printk(KERN_INFO "sockopt: set_var\n");
switch(cmd)
{
case SOCKET_OPS_SET_HELLO:
if (user == NULL)
{
ret = -1;
break;
}
ret = copy_from_user(&hello, user, len);
printk("hello from user is %d\n", hello);
break;
case SOCKET_OPS_SET_WORLD:
if (user == NULL)
{
ret = -1;
break;
}
ret = copy_from_user(&world, user, len);
printk("world from user is %s\n", world);
break;
default:
printk("undefined sock opt when set\n");
}
return ret;
}
static int get_var(struct sock *sk, int cmd, void __user *user, int *len)
{
int ret = 0;
printk(KERN_INFO "sockopt: get_var\n");
switch(cmd)
{
case SOCKET_OPS_GET_HELLO:
hello = 100;
ret = copy_to_user(user, &hello, sizeof(hello));
break;
case SOCKET_OPS_GET_WORLD:
memcpy(world, "hello,World!", sizeof("hello,world!"));
ret = copy_to_user(user, world, sizeof("hello,World!"));
break;
default:
printk("undefined sock opt when get\n");
}
return ret;
}
static struct nf_sockopt_ops my_sockopts = {
.pf= PF_INET,
.set_optmin= SOCKET_OPS_BASE,
.set_optmax= SOCKET_OPS_MAX,
.set= set_var,
.get_optmin= SOCKET_OPS_BASE,
.get_optmax= SOCKET_OPS_MAX,
.get= get_var,
};
static int __init hello_init(void)
{
int ret = 0;
printk("Loading LGW Kernel Module...\n");
ret = nf_register_sockopt(&my_sockopts);
return ret;
}
static void __exit hello_exit(void)
{
printk("Good Bye, LGW Kernel Module!\n");
nf_unregister_sockopt(&my_sockopts);
}
module_init(hello_init);
module_exit(hello_exit);用户态代码world.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define SOCKET_OPS_BASE128/ base for firewall socket options /
#define SOCKET_OPS_SET_HELLO(SOCKET_OPS_BASE + 0)
#define SOCKET_OPS_SET_WORLD(SOCKET_OPS_BASE + 1)
#define SOCKET_OPS_GET_HELLO(SOCKET_OPS_BASE + 0)
#define SOCKET_OPS_GET_WORLD(SOCKET_OPS_BASE + 1)
static inthello= 0;
static charworld16= {'\0'};
int main()
{
int sockfd;
int len;
int ret;
int hello = 1;
char world16 = "1234567";
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if(sockfd < 0)
{
printf("socket create error\n");
return -1;
}
setsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_SET_HELLO,
&hello, sizeof(hello));
len = sizeof(hello);
ret = getsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_GET_HELLO,
&hello, &len);
printf("ret is %d\n", ret);
printf("Now hello is: %d\n", hello);
setsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_SET_WORLD,
world, sizeof("1234567"));
len = sizeof(world);
ret = getsockopt(sockfd, IPPROTO_IP, SOCKET_OPS_GET_WORLD,
world, &len);
printf("ret is %d\n", ret);
printf("Now world is: %s, and len is: %d\n", world, len);
return 0;
}
本文在写作过程中参考了:http://hi.baidu.com/mnkee/blog/item/e2094936b78fe1d0a3cc2b4a.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。