深入Linux内核网络堆栈

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

深入Linux内核网络堆栈作者:bioforgealkerr@yifan.net原名:HackingtheLinuxKernelNetworkStack翻译,修改:duanjigangduanjigang1983@126.com翻译参考:raodan(raod_at_30san.com)2003-08-22第一章简介本文将描述如何利用Linux网络堆栈的窍门(不一定都是漏洞)来达到一些目的,或者是恶意的,或者是出于其它意图的。文中会就后门通讯对Netfilter钩子进行讨论,并在本地机器上实现将这个传输从基于Libpcap的嗅探器(sniffer)中隐藏。Netfilter是2.4内核的一个子系统。Netfilter可以通过在内核的网络代码中使用各种钩子来实现数据包过滤,网络地址转换(NAT)和连接跟踪等网络欺骗。这些钩子被放置在内核代码段,或者静态编译进内核,或者作为一个可动态加载/卸载的可卸载模块,然后就可以注册称之为网络事件的函数(比如数据包的接收),1.1本文论述的内容本文将讲述内核模块的编写者如何利用Netfilter的钩子来达到任何目的,以及怎样将网络传输从一个Libpcap的应用中隐藏掉。尽管Linux2.4支持对IPV4,IPV6以及DECnet的钩子,本文只提及IPV4的钩子。但是,对IPV4的大多数应用内容同样也可以应用于其他协议。出于教学目的,我们在附录A给出了一个可以工作的内核模块,实现基本的数据包过滤功能。针对本文中所列技术的所有开发和试验都在Intel机子上的Linux2.4.5系统上进行过。对Netfilte钩子行为的测试使用的是回环设备(Loopbackdevice),以太网设备和一个点对点接口的调制解调器。对Netfilter进行完全理解是我撰写本文的另一个初衷。我不能保证这篇文章所附的代码100%的没有差错,但是所列举的所有代码我都事先测试过了。我已经饱尝了内核错误带来的磨砺,而你却不必再经受这些。同样,我不会为按照这篇文档所说的任何东西进行的作所所为带来的损失而负责。阅读本篇文章的读者昀好熟悉C程序设计语言,并且对内核可卸载模块有一定的经验。如果我在文中犯了任何错误的话,请告知我。我对于你们的建议和针对此文的改进或者其它的Netfilter应用会倾心接受。1.2本文不会涉及到的方面本文并不是Netfilter的完全贯穿(或者进进出出的讲解)。也不是iptables命令的介绍。如果你想更好的学习iptables的命令,可以去咨询man手册。让我们从介绍Nerfilter的使用开始吧……….第二章各种Net-Filter钩子及其用法2.1Linux内核对数据包的处理我将尽昀大努力去分析内核处理数据包的详细内幕,然而对于事件触发处理以及之后的Netfilter钩子不做介绍。原因很简单,因为HaraldWelte关于这个已经写了一篇再好不过的文章JourneyofaPacketThroughtheLinux2.4NetworkStack,如果你想获取更多关于Linux对数据包的相关处理知识的话,我强烈建议你也阅读一下这篇文章。目前,就认为数据包只是经过了Linux内核的网络堆栈,它穿过几层钩子,在经过这些钩子时,数据包被解析,保留或者丢弃。这就是所谓的Netfilter钩子。2.2Ipv4中的Net-filter钩子Netfilter为IPV4定义了5个钩子。可以在linux/netfilter-ipv4.h里面找到这些符号的定义,表2.1列出了这些钩子。表2.1.ipv4中定义的钩子钩子名称调用时机NF_IP_PRE_ROUTING完整性校验之后,路由决策之前NF_IP_LOCAL_IN目的地为本机,路由决策之后NF_IP_FORWARD数据包要到达另外一个接口去NF_IP_LOCAL_OUT本地进程的数据,发送出去的过程中NF_IP_POST_ROUTING向外流出的数据上线之前NF_IP_PRE_ROUTING钩子称为是数据包接收后第一个调用的钩子程序,这个钩子在我们后面提到的模块当中将会被用到。其他的钩子也很重要,但是目前我们只集中探讨NF_IP_PRE_ROUTING这个钩子。不管钩子函数对数据包做了哪些处理,它都必须返回表2.2中的一个预定义好的Netfilter返回码。表2.2Netfilter返回码返回码含义NF_DROP丢弃这个数据包NF_ACCEPT保留这个数据包NF_STOLEN忘掉这个数据包NF_QUEUE让这个数据包在用户空间排队NF_REPEAT再次调用这个钩子函数NF_DROP表示要丢弃这个数据包,并且为这个数据包申请的所有资源都要得到释放。NF_ACCEPT告诉Netfilter到目前为止,这个数据包仍然可以被接受,应该将它移到网络堆栈的下一层。NF_STOLEN是非常有趣的一个返回码,它告诉Netfilter让其忘掉这个数据包。也就是说钩子函数会在这里对这个数据包进行完全的处理,而Netfilter就应该放弃任何对它的处理了。然而这并不意味着为该数据包申请的所有资源都要释放掉。这个数据包和它各自的sk_buff结构体依然有效,只是钩子函数从Netfilter夺取了对这个数据包的掌控权。不幸的是,我对于NF_QUEUE这个返回码的真实作用还不是很清楚,所在目前不对它进行讨论。昀后一个返回值NF_REPEAT请求Netfilter再次调用这个钩子函数,很明显,你应该慎重的应用这个返回值,以免程序陷入死循环。第三章注册和注销Net-Filter钩子注册一个钩子函数是一个围绕nf_hook_ops结构体的很简单的过程,在linux/netfilter.h中有这个结构体的定义,定义如下:structnf_hook_ops{structlist_headlist;/*Userfillsinfromheredown.*/nf_hookfn*hook;intpf;inthooknum;/*Hooksareorderedinascendingpriority.*/intpriority;};这个结构体的成员列表主要是用来维护注册的钩子函数列表的,对于用户来说,在注册时并没有多么重要。hook是指向nf_hookfn函数的指针。也就是为这个钩子将要调用的所有函数。nf_hookfn同样定义在linux/netfilter.h这个文件中。pf字段指定了协议簇(protocolfamily)。Linux/socket.h中定义了可用的协议簇。但是对于IPV4我们只使用PF_INET。hooknum域指名了为哪个特殊的钩子安装这个函数,也就是表2.1中所列出的条目中的一个。Priority域表示在运行时这个钩子函数执行的顺序。为了演示例子模块,我们选择NF_IP_PRI_FIRST这个优先级。注册一个Netfilter钩子要用到nf_hook_ops这个结构体和nf_register_hook()函数。nf_register_hook()函数以一个nf_hook_ops结构体的地址作为参数,返回一个整型值。如果你阅读了net/core/netfilter.c中nf_register_钩子()的源代码的话,你就会发现这个函数只返回了一个0。下面这个例子注册了一个丢弃所有进入的数据包的函数。这段代码同时会向你演示Netfilter的返回值是如何被解析的。代码列表1.Netfilter钩子的注册/*SamplecodetoinstallaNetfilterhookfunctionthatwill*dropallincomingpackets.*/#define__KERNEL__#defineMODULE#includelinux/module.h#includelinux/kernel.h#includelinux/netfilter.h#includelinux/netfilter_ipv4.h/*Thisisthestructureweshallusetoregisterourfunction*/staticstructnf_hook_opsnfho;/*Thisisthehookfunctionitself*/unsignedinthook_func(unsignedinthooknum,structsk_buff**skb,conststructnet_device*in,conststructnet_device*out,int(*okfn)(structsk_buff*)){returnNF_DROP;/*DropALLpackets*/}/*Initialisationroutine*/intinit_module(){/*Fillinourhookstructure*/nfho.hook=hook_func;/*Handlerfunction*/nfho.hooknum=NF_IP_PRE_ROUTING;/*FirsthookforIPv4*/nfho.pf=PF_INET;nfho.priority=NF_IP_PRI_FIRST;/*Makeourfunctionfirst*/nf_register_hook(&nfho);return0;}/*Cleanuproutine*/voidcleanup_module(){nf_unregister_hook(&nfho);}这就是注册所要做的一切。从代码列表1你可以看到注销一个Netfilter钩子也是很简单的一件事情,只需要调用nf_unregister_hook()函数,并将注册时用到的结构体地址再次作为注销函数参数使用就可以了。第四章基本的NetFilter数据包过滤技术4.1钩子函数近距离接触现在是我们来查看获得的数据如何传入钩子函数并被用来进行过滤决策的时候了。所以,我们需要更多的关注于nf_hookfn函数的模型。Linux/netfilter.h给出了如下的接口定义:typedefunsignedintnf_hookfn(unsignedinthooknum,structsk_buff**skb,conststructnet_device*in,conststructnet_device*out,int(*okfn)(structsk_buff*));nf_hookfn函数的第一个参数指定了表2.1给出的钩子类型中的一种。第二个参数更有趣,它是一个指向指针(这个指针指向一个sk_buff类型的结构体)的指针,它是网络堆栈用来描述数据包的结构体。这个结构体定义在linux/skbuff.h中,由于这个结构体的定义很大,这里我只着重于它当中更有趣的一些域。或许sk_buff结构体中昀有用的域就是其中的三个联合了,这三个联合描述了传输层的头信息(例如UDP,TCP,ICMP,SPX),网络层的头信息(例如ipv4/6,IPX,RAW)和链路层的头信息(Ethernet或者RAW)。三个联合相应的名字分别为:h,nh和mac。根据特定数据包使用的不同协议,这些联合包含了不同的结构体。应当注意,传输层的头和网络层的头极有可能在内存中指向相同的内存单元。在TCP数据包中也是这样的情况,h和nh都是指向IP头结构体的指针。这就意味着,如果认为h-th指向TCP头,从而想通过h-th来获取一个值的话,将会导致错误发生。因为h-th实际指向IP头,等同于nh-iph。其他比较有趣的域就是len域和data域了。len表示包中从data开始的数据总长度。因此,现在我们就知道如何通过一个skbuff结构体去访问单个的协议头或者数据包本身的数据。还有什么有趣的数据位对于Netfilter的钩子函数而言是有用的呢?跟在sk_buff之后的两个参数都是指向net_device结构体的指针。net_devices结构体是Linux内核用来描述各种网络接口的。第一个结构体,in,代表了数据包将要到达的接口,当然out就代表了数据包将要离开的接口。有很重要的一点必须认识到,那就是通常

1 / 51
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功