Linux Netfilter 技术(2)-代码

概述

Linux Netfilter技术(1)-概述已经介绍了Netfilter的基本概念和框架,主要是了解了Netfilter框架的Hook原理,这篇主要介绍如何基于Netfiter框架实现自己的hook函数。如果google或者百度大部分都是基于老接口的示例nf_register_hook,在kernel 4.13.x之后都是新接口nf_register_net_hook,接下来主要是基于4.18的kernel讲解一下netfilter hook的例子。

hook结构体信息

为了注册一个钩子,需要填充nf_hook_ops结构体,包括钩子函数、设备、协议类型、钩子函数位置以及优先级,具体的定义如下:

struct nf_hook_ops {
    /* User fills in from here down. */
    nf_hookfn       *hook;
    struct net_device   *dev;
    void            *priv;
    u_int8_t        pf;
    unsigned int        hooknum;
    /* Hooks are ordered in ascending priority. */
    int         priority;
};

贴出来代码里的具体内容,一一说一下里面涉及到的内容

static const struct nf_hook_ops ipv4_test_in_ops = {
        .hook   = nf_ipv4_test_hook,
        .pf     = NFPROTO_IPV4,
        .hooknum = NF_INET_LOCAL_IN,
        .priority = NF_IP_PRI_FIRST,
};
  • .hook = nf_ipv4_test_hook,钩子函数,它的函数参数如下:
    static unsigned int nf_ipv4_test_hook(void *priv,
                                         struct sk_buff *skb,
                                         const struct nf_hook_state *state);

    我们主要使用skb这个参数来对数据流进程处理

  • .pf = NFPROTO_IPV4,协议类型,除了IPV4还有如下几个:
    enum {
    NFPROTO_UNSPEC =  0,
    NFPROTO_INET   =  1,
    NFPROTO_IPV4   =  2,
    NFPROTO_ARP    =  3,
    NFPROTO_NETDEV =  5,
    NFPROTO_BRIDGE =  7,
    NFPROTO_IPV6   = 10,
    NFPROTO_DECNET = 12,
    NFPROTO_NUMPROTO,
    };
  • .hooknum = NF_INET_LOCAL_IN
    钩子函数入口,这个参数代表我们实在Netfilter框架的什么位置调用该函数,还有其他一些的定义:

    enum nf_inet_hooks {
    NF_INET_PRE_ROUTING,
    NF_INET_LOCAL_IN,
    NF_INET_FORWARD,
    NF_INET_LOCAL_OUT,
    NF_INET_POST_ROUTING,
    NF_INET_NUMHOOKS
    };
  • .priority = NF_IP_PRI_FIRST,因为同一个hook_num可以定义多个钩子函数,为了保证所有的有可以执行,所以有设置优先级,这个参数就是设置钩子函数的优先级的
    enum nf_ip_hook_priorities {
    NF_IP_PRI_FIRST = INT_MIN,
    NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
    NF_IP_PRI_CONNTRACK_DEFRAG = -400,
    NF_IP_PRI_RAW = -300,
    NF_IP_PRI_SELINUX_FIRST = -225,
    NF_IP_PRI_CONNTRACK = -200,
    NF_IP_PRI_MANGLE = -150,
    NF_IP_PRI_NAT_DST = -100,
    NF_IP_PRI_FILTER = 0,
    NF_IP_PRI_SECURITY = 50,
    NF_IP_PRI_NAT_SRC = 100,
    NF_IP_PRI_SELINUX_LAST = 225,
    NF_IP_PRI_CONNTRACK_HELPER = 300,
    NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
    NF_IP_PRI_LAST = INT_MAX,
    };

注册/卸载钩子函数

int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg,
              unsigned int n);
int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg);

void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
                 unsigned int hookcount);
void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg);

具体的函数
注册:

static int __init init_nf_test(void) {
  ...
  ret =nf_register_net_hook(&init_net, &ipv4_test_in_ops);
 ...
  return 0;
}

里面的init_net定义如下

extern struct net init_net;

卸载:

  nf_unregister_net_hook(&init_net, &ipv4_test_in_ops);

代码示例

在 NF_INET_LOCAL_IN 处注册一个hook函数,打印包的m源和目的MAC地址和IP 地址

static unsigned int nf_ipv4_test_hook(void *priv,
                                   struct sk_buff *skb,
                                   const struct nf_hook_state *state)
{
  struct ethhdr *eth_header;
  struct iphdr *ip_header;

  eth_header = (struct ethhdr *)(skb_mac_header(skb));
  ip_header = (struct iphdr *)(skb_network_header(skb));

  if('0' != eth_header->h_dest[0]){

        hdr_dump(eth_header);
  }

  if('0' != ip_header->saddr){

        printk("src IP:'"NIPQUAD_FMT"', dst IP:'"NIPQUAD_FMT"' \n",
        NIPQUAD(ip_header->saddr), NIPQUAD(ip_header->daddr));
  }
  return NF_ACCEPT;
}

static int __init init_nf_test(void) {
  int ret;
  ret =nf_register_net_hook(&init_net, &ipv4_test_in_ops);
  if (ret < 0) {
    printk("register nf hook fail\n");
    return ret;
  }
  printk(KERN_NOTICE "register nf test hook\n");
  return 0;
}

static void __exit exit_nf_test(void) {

  nf_unregister_net_hook(&init_net, &ipv4_test_in_ops);
  printk(KERN_NOTICE "unregister nf test hook\n");

}

module_init(init_nf_test);
module_exit(exit_nf_test);

粘贴了部分代码,源码地址:
Netfliter_hook源码
实验结果:

[76291.212066] [MAC_DES:52,54,0,df,93,bf  MAC_SRC: 52,54,0,11,e4,a6 Prot:8]
[76291.212067] src IP:'192.168.122.1', dst IP:'192.168.122.161' 
[76291.213067] [MAC_DES:52,54,0,df,93,bf  MAC_SRC: 52,54,0,11,e4,a6 Prot:8]
[76291.213068] src IP:'192.168.122.1', dst IP:'192.168.122.161

小结:主要目的是使用nf_register_net_hook函数,利用Netfiler框架做一下小实验,显示包的一些信息,后面会继续说一下,Netfilter是如何调用hook函数的。

参考链接

https://github.com/Douane/douane-dkms/issues/26
http://wiki.dreamrunner.org/public_html/Linux/Networks/netfilter.html

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇