linux 内核网络钩子类型

转载 2018年04月16日 11:13:28
深度好文
Netfilter是Linux 2.4内核的一个子系统,Netfiler使得诸如数据包过滤、网络地址转换(NAT)以及网络连接跟踪等技巧成为可能,这些功能仅通过使用内核网络代码提供的各式各样的hook既可以完成。这些hook位于内核代码中,要么是静态链接的,要么是以动态加载的模块的形式存在。可以为指定的网络事件注册相应的回调函数,数据包的接收就是这样一个例子。

钩子函数(回调函数)也是系统内核为驱动程序提供的一些特定的函数,在驱动程序中某个变量的状态发生改变或将要改变或改变完成时,将会自动调用该回调函数,在netfilter中的状态就有五个(针对IPV4):

hook调用的时机

NF_IP_PRE_ROUTING //在完整性校验之后,选路确定之前
NF_IP_LOCAL_IN //在选路确定之后,且数据包的目的是本地主机
NF_IP_FORWARD //目的地是其它主机地数据包
NF_IP_LOCAL_OUT //来自本机进程的数据包在其离开本地主机的过程中
NF_IP_POST_ROUTING //在数据包离开本地主机“上线”之前

而netfilter的返回值有5种:
返回值 含义

NF_DROP //丢弃该数据包
NF_ACCEPT //保留该数据包
NF_STOLEN //忘掉该数据包
NF_QUEUE //将该数据包插入到用户空间
NF_REPEAT //再次调用该hook函数

如果要注册一个钩子函数,就要先申明一个nf_hook_ops 结构体,然后对其结构体里面的各个属性进行相应的赋值

struct nf_hook_ops
{
    struct list_head list;
    nf_hookfn *hook;
    int pf;
    int hooknum;
    int priority;
};

list:链表头,用来把各个处理函数组织成一个表,初始化为{NULL,NULL};
hook:我们定义的处理函数的指针,它的返回值必须为前面所说的几个常量之一;
pf:协议族,表示这个HOOK属于哪个协议族;
hooknum:我们想要注册的钩子,取值为五个钩子之一;
priority:优先级,目前Netfilter定义了一下几个优先级,取值也小优先级也高,我们可以根据需要对各个优先级加减一个常量得到符合我们需要的优先级。

NF_IP6_PRI_FIRST = INT_MIN
NF_IP6_PRI_CONNTRACK = -200
NF_IP6_PRI_MANGLE = -150
NF_IP6_PRI_NAT_DST = -100
NF_IP6_PRI_FILTER = 0
NF_IP6_PRI_NAT_SRC = 100
NF_IP6_PRI_LAST = INT_MAX

IP层的五个HOOK点的位置如下图所示 :

  --->[1]--->[ROUTE]--->[3]--->[4]--->
                 |          ^
                 |          |
                 |       [ROUTE]
                 v          |
                [2]        [5]
                 |          ^
                 |          |
                 v          |
               [ Local process]

[1]:NF_IP_PRE_ROUTING:刚刚进入网络层的数据包通过此点(刚刚进行完版本号,校验和等检测),源地址转换在此点
进行;
[2]:NF_IP_LOCAL_IN:经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
[3]:NF_IP_FORWARD:要转发的包通过此检测点,FORWORD包过滤在此点进行;
[4]:NF_IP_LOCAL_OUT:本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行;
[5]:NF_IP_POST_ROUTING:所有马上便要通过网络设备出去的包通过此检测点,内置的目的地址转换功能(包括地址伪装)在此点进行。

以下是一个例子程序:

#define __KERNEL__
#define MODULE

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>


static struct nf_hook_ops nfho;


unsigned int hook_func( unsigned int hooknum,
  struct sk_buff **skb,
   const struct net_device *in,
    const struct net_device *out,
     int (*okfn)(struct sk_buff *) )
{
    return NF_DROP;          
}

int init_module()
{

    nfho.hook = hook_func;        
    nfho.hooknum  = NF_IP_PRE_ROUTING;
    nfho.pf       = PF_INET;
    nfho.priority = NF_IP_PRI_FIRST;  
    nf_register_hook(&nfho); //将用户自己定义的钩子注册到内核中
    return 0;
}

void cleanup_module()
{
    nf_unregister_hook(&nfho); //将用户自己定义的钩子从内核中删除
}

在netfilter中注册钩子函数即可,一个参考实现

#include   <linux/module.h>
#include   <linux/init.h>
#include   <linux/kernel.h>
#include   <linux/netfilter.h>
#include   <linux/netfilter_ipv4.h>
#include   <linux/ip.h>
#include   <net/ip.h>
#include   <linux/udp.h>
#include   <linux/in.h>
#include   <linux/skbuff.h>
#include   <linux/netdevice.h>
#include   <linux/if_ether.h>
#include   <linux/if.h>

//define interface packet coming from
static char *in_dev= "eth0 ";
MODULE_PARM(in_dev, "s ");

//capture packet and analyse it
static unsigned int packet_cap(unsigned int hooknum,struct sk_buff **pskb,
 const struct net_device *in,const struct net_device *out,int(*okfn)(struct sk_buff *))
{
 unsigned int ret=NF_ACCEPT;

 if(in&&(strcmp(in_dev,in->name)!=0))
  goto no_interest;

 struct iphdr *iph=(*pskb)->nh.iph;
 unsigned int data_len=(*pskb)->len;

 void *protoh=(u_int32_t *)iph+iph->ihl;
 data_len-=iph->ihl*4;

 switch(iph->protocol)
 {
  case IPPROTO_TCP:  
  {
   struct tcphdr *tcph=protoh;

   __u16 sport=ntohs(tcph->source);
   if(sport%2==0)   ret=NF_DROP;
   printk( "packet   sport=%d\n ",sport);
  break;  
  }
  case IPPROTO_UDP:  
  {
   struct   udphdr   *udph=protoh;

   __u16 sport=ntohs(udph->source);
   if(sport%2==0)   ret=NF_DROP;
   break;  
  }  
  default:
   break;
 }  

no_interest:
 return ret;
}

//define one hook function
static struct nf_hook_ops hook_pcap = {
 {NULL,NULL},
 packet_cap,
 PF_INET,
 NF_IP_LOCAL_IN,
 NF_IP_PRI_FILTER+1
};

static int __init init(void)
{
 return nf_register_hook(&hook_pcap);
}

static void __exit fini(void)
{
 nf_unregister_hook(&hook_pcap);
}

module_init(init);
module_exit(fini);

MODULE_LICENSE( "GPL ");  

往linux内核挂钩子--什么应该什么不应该

总是在网上看到有人讨论拦截linux的系统调用,方法数量可谓海量,几乎都是自己写的内核模块,可是这种方式有什么意义呢,模块都能加载了还有什么做不 到的呢,要知道linux的可加载内核模块功能十分强大,...
  • dog250
  • dog250
  • 2010-02-09 22:20:00
  • 4182

Linux 的简单钩子

在Windows的游戏外挂开发上,钩子(hook)是一个很常见的技术。这里我们不想讨论钩子是什么意思和在Windows上是如何实现的,只是来简单地学习一下Linux的钩子。 首先来确定一个函数,要一个...
  • ypist
  • ypist
  • 2014-03-18 01:37:30
  • 4994

内核钩子实例(稳定)

#include #include #pragma pack(1)typedef struct ServiceDescriptorEntry {    unsigned int *ServiceTab...
  • iiprogram
  • iiprogram
  • 2008-03-21 09:16:00
  • 1305

Linux 钩子函数 实现数据包的过滤实例

记录一下,方便查询 洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(上) http://blog.chinaunix.net/uid-23069658-...
  • hack8
  • hack8
  • 2013-05-05 11:21:40
  • 986

内核钩子2.0

  • 2012年07月26日 09:05
  • 169KB
  • 下载

Rootkit技术之内核钩子原理

我们知道,应用程序总是离不开系统内核所提供的服务,比如它要使用内存的时候,只要跟操作系统申请就行了,而不用自己操心哪里有空闲的内存空间等问题,实际上,这些问题是由操作系统的内核来代劳的。站在黑客的角度...
  • cosmoslife
  • cosmoslife
  • 2013-09-04 21:17:14
  • 856

linux 内核参数调整优化网络

Linux系统内核设置优化tcp网络,# vi /etc/sysctl.conf,添加以下内容 net.ipv4.tcp_syncookies = 1  表示开启SYN Cookies。当出现SYN...
  • neubuffer
  • neubuffer
  • 2013-11-21 13:48:58
  • 8442

Linux内核参数——优化网络速度

所有的TCP/IP调优参数都位于/proc/sys/net/目录. 例如, 下面是最重要的一些调优参数, 后面是它们的含义:    1. /proc/sys/net/core/rmem_max — ...
  • huasonl88
  • huasonl88
  • 2017-03-20 14:38:25
  • 259

钩子的类型

WH_CALLWNDPROC     发送到窗口的消息。由SendMessage触发 WH_CALLWNDPROCRET  发送到窗口的消息。由SendMessage处理完成返回时触发 WH_GE...
  • G1036583997
  • G1036583997
  • 2014-10-15 19:22:13
  • 1476

Linux内核网络:实现和理论(2014)-第十章 IPsec

... XFRM框架       IPsec基于XFRM(读作“transform”)框架实现,该框架源于USAGI项目,其目标是提供一种产品化的IPv6和IPsec协议栈。术语“transform”...
  • naipeng
  • naipeng
  • 2017-05-10 21:04:55
  • 764
收藏助手
不良信息举报
您举报文章:linux 内核网络钩子类型
举报原因:
原因补充:

(最多只允许输入30个字)