描述
原始套接字具有广泛的用途,特别是用于自定义协议(标准协议TCP、UDP和ICMP等外)的数据收发。在Linux下拦截套接字IO的一般方法是拦截对应的套接字系统调用,对于发送为sendmsg和sendto,对于接收为recvmsg和recvfrom。这种方法虽然也能拦截原始套接字IO,但要先判断套接字的类型,如果为SOCK_RAW(原始套接字类型),那么进行拦截处理,这样一来由于每次IO都要判断套接字类型,性能就比较低了。因此为了直接针对原始套接字来拦截,提高性能,发明了本方法。
本方法可用于防火墙或主机防护系统中,丢弃接收和发送的攻击或病毒数据包。
特点
运行在内核态,直接拦截所有进程的原始套接字IO,支持IPv4和IPv6。
实现
原理
在Linux内核网络子系统中,struct proto_ops结构提供了协议无关的套接字层到协议相关的传输层的转接,而IPv4协议族中内置的inet_sockraw_ops为它的一个实例,对应着原始套接字。因此先找到inet_sockraw_ops,再替换它的成员函数指针recvmsg和sendmsg,就可以实现拦截了。下面以IPv4为例(IPv6同理),说明几个流程。
搜索inet_sockraw_ops
该流程在挂钩IO前进行。由于inet_sockraw_ops为Linux内核未导出的内部符号,因此需要通过特别的方法找到它,该特别的方法基于这样的一个事实:
◆ 所有原始套接字接口均存放在以SOCK_RAW为索引的双向循环链表中,而inet_sockraw_ops就在该链表的末尾。
◆ 内核提供了注册套接字接口的API inet_register_protosw,对于原始套接字类型,该API将输入的套接字接口插入到链表头后面。
算法如下
注册p前或注销p后,链表如下
注册p后,链表如下
挂钩IO
该流程在内核模块启动时进行。
卸钩IO
该流程在内核模块退出时进行。
运行部署
该方法实现在Linux内核模块中,为了防止其它内核模块可能也注册了原始套接字接口,因此需要在操作系统启动时优先加载。
posted on 2016-07-14 10:27
春秋十二月 阅读(2466)
评论(3) 编辑 收藏 引用 所属分类:
Network