Netfilter学习笔记

I am definitely no kernel guru and the information provided by this document may be wrong. So don’t expect too much, I’ll always appreciate Your comments and bugfixes.

Netfilter

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

Netfilter 中定义了五个关于 IPv4 的 hook,对这些符号的声明可以在 netfilter_ipv4.h 中找到,可用的 IP HOOK 如下:

#define NF_IP_PRE_ROUTING   0   // 在进行完整性检查之后,可以截获接收的所有报文,包括目的地址是自己的报文和需要转发的报文;目的IP地址转换在此点
#define NF_IP_LOCAL_IN      1   // 路由决策后,可以截获目的地址是自己的报文,INPUT 包过滤在这里进行
#define NF_IP_FORWARD       2   // 截获所有转发的报文,FORWARD 在这里进行过滤
#define NF_IP_LOCAL_OUT     3   // 可以截获自身发出的所有报文(不包括转发),OUTPUT 过滤在这里进行
#define NF_IP_POST_ROUTING  4   // 可以截获发送的所有报文,包括自身发出的报文和转发的报文

img

在 hook 函数完成了对数据包所需的任何的操作之后,它们必须返回下列预定义的 Netfilter 返回值中的一个:

#define NF_DROP     0     // 丢弃数据包,不在继续
#define NF_ACCEPT   1     // 正常传输报文
#define NF_STOLEN   2     // Netfilter 模块接管该报文,不再继续传输
#define NF_QUEUE    3     // 对该数据报进行排队,通常用于将数据报提交给用户空间进程处理
#define NF_REPEAT   4     // 再次调用该钩子函数
#define NF_STOP     5     // 继续正常传输报文

Note:NF_ACCEPT 和 NF_STOP 都表示报文通过了检查,可以正常向下流通。

  • NF_ACCEPT 表示报文通过了某个 HOOK 函数的处理,下一个 HOOK 函数可以接着处理了
  • NF_STOP 表示报文通过了某个 HOOK 函数的处理,后面的 HOOK 函数你们就不要处理了

注册和注销Netfilter hook

注册一个 hook 函数是围绕 nf_hook_ops 数据结构,数据结构的定义如下:

// https://elixir.bootlin.com/linux/v5.11.2/source/include/linux/netfilter.h#L77
typedef unsigned int nf_hookfn(void *priv,	// priv:私有数据
             struct sk_buff *skb,			// 正在处理的报文
             const struct nf_hook_state *state);	// 将相关参数都将存储到 state 中

struct nf_hook_ops {
  nf_hookfn   *hook;	// hook 函数
  struct net_device *dev;	// 设备
  void      *priv;	// 
  u_int8_t    pf;	// 协议族
  unsigned int    hooknum;	// hook 触发点的编号
  int     priority;	// 优先级
};

struct nf_hook_state {
  unsigned int hook;
  u_int8_t pf;
  struct net_device *in;	// 用于描述数据包到达的接口
  struct net_device *out;	// 用于描述数据包离开的接口
  struct sock *sk;
  struct net *net;
  int (*okfn)(struct net *, struct sock *, struct sk_buff *);
};
// 参数 in 只用于NF_IP_PRE_ROUTING和NF_IP_LOCAL_IN,
// 参数out只用于NF_IP_LOCAL_OUT和NF_IP_POST_ROUTING

注册一个 Netfilter hook 需要调用 nf_register_net_hook() 函数,以及用到一个 nf_hook_ops 数据结构。nf_register_net_hook()函数以一个 nf_hook_ops 数据结构的地址作为参数并且返回一个整型的值。 代码如下:

// https://elixir.bootlin.com/linux/v5.11.2/source/net/netfilter/core.c#L557
int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg,
        unsigned int n)
{
...
  for (i = 0; i < n; i++) {
    err = nf_register_net_hook(net, &reg[i]); // 注册 hook 函数
    if (err)
      goto err; // 注册失败
  }
  return 0;
err:
  if (i > 0) // 注销 hook 函数
    nf_unregister_net_hooks(net, reg, i);
  return err;
}

触发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值