struct file {
....
/* needed for tty driver, and maybe others */
void *private_data;
....
};更一般的,该字段作为结构体的最后一个字段存在,这已经很接近OO的思想了,但是却永远无法达到,因为,一个private字段是作为结构体内部的扩展,即对象的属性扩展,而不是类型本身的扩展。怎么说呢?如果我建立了一个对象,即:struct file *f = ....; f->private_data = ...;
struct txtfile_extends_file {
struct file f;
void *private;
};这么做和直接在file加入private_data相比,更能体现OO的思想。如果直接在file结构体加入private字段,那么任何人都可以对任何file实例的private字段进行替换和解释,只要它拿到file实例即可,但是如果扩展的是struct file类型,那么只有类型的定义者和理解类型定义的人才能对其进行操作。举例如下。如果直接在file结构体加入private,那么下面的赋值就是合法的:f1->private = a; ... f1->private = b;这样一来,除非频繁加锁,否则一个file的扩展就是不稳定的,它可以在任何地点被重定义。反之,如果是对struct file的定义进行扩展的话,那么
struct txtfile1_extends_file {
struct file f;
void *private1;
};和struct txtfile2_extends_file {
struct file f;
void *private2;
};就是两个类型,任何时候,通过txtfile1的对象引用private2字段都是非法的,当然上述情况下你完全可以通过强制类型转换达到目的,但是请注意,C语言本身对类型检查就不严格。你也可以通过内存操作来达到任何不可告人的目的,但是你要知道,计算机世界的任何事情都可以通过内存操作来进行,如果你为了炫技巧非要采用那么原始的操作,那也无妨。void __init skb_init(void)
{
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
sizeof(struct sk_buff) + sizeof(char *),
0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache",
(2*(sizeof(struct sk_buff) + sizeof(char *))) +
sizeof(atomic_t),
0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
}这样你就可以在其它代码不知情的情况下扩展skb了,比如定义以下结构体:struct data_extends_skb {
struct sk_buff skb;
char *info;
};在PREROUTING的地方调用:
struct data_extends_skb *des = (struct data_extends_skb *)skb; strcpy(des->info, "abcdefg", 6);然后可以在任何后续的地方将info取出来。但是这有一个问题,那就是如果出现第二个执行绪,它完全可以将info的赋值修改掉,即便它不明白结构体data_extends_skb的定义,也不知道info字段的具体名字,它如果这么做:
memcpy(skb + 1, 0, sizeof(char *));也会取消掉代码作者的本意。当然,这在C语言中是没有办法的。
#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) ({int __ret; if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1) __ret = (okfn)(skb); __ret;})
完全可以定义成:#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) ({struct sk_buff *__skb2, __ret; if ((__skb2=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) != NULL) __ret = (okfn)(__skb2); __ret;})
....// nf_hook_thresh的修改如此一来,就可以在Netfilter中实现skb的重定义(我还没有勇气对整个协议栈开刀,要改的地方太多太多了,还是只对Netfilter开刀吧),这是意义非凡的,迎合了OO思想的向上转型,即任何一个特殊的类的对象都可以转型为更加一般的其基类对象。看似操作的是sk_buff对象,实际上它只是一个基类对象。在Netfilter的hook中,你完全可以这样:struct sub_extends_skb {
struct sb_buff skb;
type1 v1;
type2 v2;
type3 v3;
...
};
struct sub_extends_skb *sub_construct (struct sb_buff *skb)
{
struct sub_extends_skb = _k_malloc_and_skb_copy(sizeof(sub_extends_skb), skb);
ses->v1 = ...;
...
return ses;
}
struct sub_extends_skb *ss;
if (...) {
ss = construct(skb);
} else {
ss = skb;
}
... // process
return ss;
只要可以修改skb的指针了,那就意味着可以重新定义skb的类型了,这也意味着扩展skb成了可能。 需要注意的是,等到需要确定一个skb到底是什么类型的时候,怎么办呢?OO语言内置的有类型检查,反射等机制,比如JAVA的instance of宏等,可在Linux内核这种底层C写就的代码中,如何来做呢?C语言没有高级OO语言的种种内置特性,这完全需要程序员自己来解决这个问题,比如你不能对一个原生的skb取v2的值,而这个是不能保证的,正如你可以写下以下的代码一样:char *p = (char *)0; *p = ‘a‘; ...越是高级的语言总是让人不关注语言以及计算机机制本身,而专注于自己的业务逻辑,但是以计算机为本业的系统程序员,或者网络安全系统程序员,却最好不要去用什么高级的语言,因为你的业务逻辑就是要搞定计算机或者网络所呈现的缤纷复杂,而不是和一群穿西服的人论战...这也是一个思想!
如何任意扩展sk_buff而不重新编译内核,布布扣,bubuko.com
原文:http://blog.csdn.net/dog250/article/details/23604717