logo资料库

Linux netfilter 学习笔记.pdf

第1页 / 共170页
第2页 / 共170页
第3页 / 共170页
第4页 / 共170页
第5页 / 共170页
第6页 / 共170页
第7页 / 共170页
第8页 / 共170页
资料共170页,剩余部分请下载后查看
1.1 xt_table
1.2 xt_table_info
1.3 ipt_entry
1.3.1 ipt_ip
1.4 ipt_entry_match
1.4.1 xt_match
1.5 ipt_standard_target
1.6 ipt_entry_target
1.6.1 xt_target
1 ipt_register_table
1.1 xt_alloc_table_info
1.2 translate_table
1.2.1 check_entry_size_and_hooks
1.2.3 check_entry
1.3 xt_register_table
2 do_replace
ipt_do_table
1.1 ip_packet_match
1.2 IPT_MATCH_ITERATE
1.3 do_match
1. Filter模块初始化
1.1 Filter表的初始化
1.1.1 xt_table filter表初始化
1.1.2 ipt_replace repl
1.2 hook函数的注册
1.2.1 nf_hook_ops初始化
2 filter模块的初始化函数
1. 相应的数据结构
1.1 nf_conn
1.2 nf_conntrack_tuple
1.2.1 nf_conntrack_man
1.3 nf_conntrack_helper
1.4 nf_conntrack_proto
1.5 nf_conntrack_l3proto
1.6 nf_conntrack_protocol
1.7 nf_conntrack_expect
1.全局初始化
1.1 nf_conntrack_init
1.2init_or_cleanup
2 Ipv4 连接跟踪模块Hook回调函数的注册
3.三层协议、四层协议中连接模块相关的全局变量定义
3.1 nf_conntrack_l3proto_ipv4
3.1.1 ipv4_pkt_to_tuple
3.1.2 ipv4_invert_tuple
3.1.3 ipv4_prepare
3.1.4 ipv4_tuple_to_nfattr
3.1.5 ipv4_nfattr_to_tuple
3.2 nf_conntrack_protocol_tcp4
1.ipv4_conntrack_defrag
2.ipv4_conntrack_in
2.1 resolve_normal_ct
2.1.1 nf_ct_get_tuple
2.1.2 nf_conntrack_find_get
2.1.2.3 连接跟踪项的异步垃圾处理机制
2.1.2.3.1death_by_timeout
2.1.2.3.2nf_ct_put&nf_conntrack_put
2.1.2.3.3 destroy_conntrack
2.1.2.4 连接跟踪项的同步垃圾处理机制
3.ipv4_conntrack_help
4.ipv4_confirm&nf_conntrack_confirm
4.1 __nf_conntrack_confirm
1.NAT的原理
1.1 SNAT
1.2 DNAT
2. NAT模块的初始化
2. 1nat表的注册
2.2 NAT模块的target注册
2.2.1 SNAT target的注册
2.2.2 DNAT target的注册
2.3 NAT模块的hook函数的注册
2.4 NAT模块四层协议相关的结构注册
1. NAT相关的hook函数分析
1.1 nf_nat_in
1.2 nf_nat_out
1.3nf_nat_local_fn
1.4 LOCAL_IN hook
1.5 通用NAT转换函数
1.5.1 nf_nat_fn
1.5.1.1 nf_nat_initialized
1.5.1.2 alloc_null_binding_confirmed
1.5.1.3 alloc_null_binding
1.5.1.4 nf_nat_rule_find
1.5.1.5 nf_nat_packet
1.5.2 nf_nat_setup_info
1.5.2.1 get_unique_tuple
1.5.2.1.1 find_appropriate_src
1.5.2.1.2 nf_nat_used_tuple
2. target相关的函数分析
2.1 SNAT target
2.2 DNAT target
2.3 xt_target masquerade
3.实例分析
3.1 SNAT
3.1.1环境说明
3.1.2 数据SNAT转换分析
3.2 DNAT
3.2.1 环境说明
3.2.2 数据的DNAT分析
1.SNAT转换的特殊处理
2.UDP打洞
3.SNAT模块支持UDP打洞吗
Linux netfilter 笔记之 一 NF_HOOK分析 写在前面: 对于linux netfilter机制,是怀着敬畏的心情开始代码学习的,总感觉linux netfilter机制比较强大,总不敢轻易写下分析文档,但为了提升与扩展自己的知识面,特写下此系列的学习文档,以推动自己不断前行,不断学习。 一、netfilter介绍 Linux netfilter就是借助一整套的 hook 函数的管理机制,实现数据包在三层以上的过滤、地址转换(SNAT、DNAT)、基于协议的连接跟踪。我们所说的内核的netfilter,应该包括二层数据的filter操作,以及对三层及三层以上数据的filter等操作。 只不过二层的filter实现与三层及三层也上的filter实现有所不同。其中二层的filter与应用层程序ebtables结合使用,而三层及以上的filter结合iptables使用。但是二层filter与三层filter使用的都是统一的hook机制。 下面我们就在分析三层及三层以上的netfilter之前,分析一下整体的hook机制及工作流程 linux抽象出整体的hook架构,通过在以下几个数据流经点添加hook机制,为实现netfilter提供基础框架: NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING。 这五个点在数据的流经方向如下图: 二、数据结构 1、nf_hook_ops Hook点回调函数相关的数据结构,其是nf hook机制的重要数据结构,各成员的意义如下: struct nf_hook_ops { struct list_head list; //链表结构,实现hook函数链接 /* User fills in from here down. */ nf_hookfn *hook;//hook处理函数
struct module *owner;//模块所属 int pf;//协议号 int hooknum;//hook 点 /* Hooks are ordered in ascending priority. */ int priority;//优先级 }; 2、 nf_hookfn Hook 回调函数的定义 hooknum:hook 点 skb:数据包 in:数据包入口设备 out:数据包出口设备 okfn:是个函数指针,当所有的该 HOOK 点的所有登记函数调用完后, 调用该函数 typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)); 3、nf_hooks nf_hooks 是一个二维数组,该二维数组的每一个成员均是一个链表。每一个链表的所有 节点都代表一个协议在一个 hook 点上的所有的 hook 成员其中协议有 32 个,而 hook 点有 8 个 , 目 前 使 用 的 是 5 个 , 分 别 为 NF_IP_PRE_ROUTING 、 NF_IP_LOCAL_IN 、 NF_IP_FORWARD、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING。而在同一个链表上, 节点是按照优先级顺序排列的,优先级值最小的 hook 变量存在链表的最前面,优先执行。 struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; 三、HOOK 机制的注册、执行相关的函数 1、hook 注册函数 nf_register_hook 功能: 将一个新的 hook 结构添加 nf_hooks 数组的相应的成员链表中 A 根据协议号、hook 点,确定链表 B 根据优先级将该 hook 结构添加到链表的合适位置 注意:访问 nf_hooks,需要添加自旋锁 int nf_register_hook(struct nf_hook_ops *reg) { struct list_head *i; spin_lock_bh(&nf_hook_lock); list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) { if (reg->priority < ((struct nf_hook_ops *)i)->priority) break;
} list_add_rcu(®->list, i->prev); spin_unlock_bh(&nf_hook_lock); synchronize_net(); return 0; } 2、Hook 注销函数 nf_unregister_hook 功能: 将一个 hook 结构从 nf_hooks 数组的相应的成员链表中删除 删除操作就是平常的删除链表成员的操作,比较简单 void nf_unregister_hook(struct nf_hook_ops *reg) { } spin_lock_bh(&nf_hook_lock); list_del_rcu(®->list); spin_unlock_bh(&nf_hook_lock); synchronize_net(); 3、hook 执行函数 目前调用执行 hook 回调函数的为宏 NF_HOOK NF_HOOK 功能:执行 hook 回调函数 该宏调用 NF_HOOK_THRESH 来实现具体功能 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN) NF_HOOK_THRESH 功能:执行 hook 回调函数 相比于 NF_HOOK,该宏增加了一个变量 thresh,thresh 是变量 hook 回调函数的优先级 A 该宏调用 nf_hook_thresh 来实现遍历 hook 回调函数并执行操作后返回执行结果 B 若返回值为 1,则继续调用回调函数 okfn 进行后续操作。 #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \ ({int __ret; \ if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh, 1)) == 1)\ __ret = (okfn)(skb); \ __ret;}) NF_HOOK_COND: 与 NF_HOOK_THRESH 相比,将 thresh 值设置了默认值,而增加了 cond 变量,这两个宏最 终都会调用函数 nf_hook_thresh
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \ ({int __ret; \ if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\ __ret = (okfn)(skb); \ __ret;}) nf_hook_slow: 这个函数才是真正干活的函数,真正遍历 hook 链表并执行 hook 回调函数。 pf:协议号 hook:hook 点 pskb:数据包 indev:数据包入口函数 outdev:数据包出口函数 okfn:回调函数(此处不执行) hook_thresh:起始优先级,只执行该 hook 点上优先级大于该值所有 hook 函数 功能:遍历协议号为 pf,hook 点为 hook 的链表,找到所有优先级大于或等于 hook_thresh 的所有 hook 结构,执行每一个 hook 结构的 hook 回调函数。 若调用 nf_iterate 的返回值是 NF_DROP,则释放 skb,且返回错误 若返回值为 NF_ACCEPT、NF_STOP,则返回 1 表示允许数据包继续前行 若是 NF_QUEUE,则将数据方式 netfilter 的队列中,数据包可以从内核传递到 用户层处理,并将处理结果返回。 int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb, { struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *), int hook_thresh) struct list_head *elem; unsigned int verdict; int ret = 0; /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); elem = &nf_hooks[pf][hook]; next_hook: verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
outdev, &elem, okfn, hook_thresh); if (verdict == NF_ACCEPT || verdict == NF_STOP) { ret = 1; goto unlock; } else if (verdict == NF_DROP) { kfree_skb(*pskb); ret = -EPERM; } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { NFDEBUG("nf_hook: Verdict = QUEUE.\n"); /*nf_queue 是 netfilter 的基本机制--队列模型, 可以经内核数据包递交到用户层处理,并根据用户态的处理结果,对数据包进行相 应的操作*/ if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn, verdict >> NF_VERDICT_BITS)) goto next_hook; } unlock: rcu_read_unlock(); return ret; } 上面就是 HOOK 机制涉及到的主要的函数,HOOK 机制还是比较好理解的,就是这样的机 制作为基石,为 netfilter 的实现提供了坚实的基础,使 netfilter 能够实现很强大的功能。 四、实践 下面主要是通过上面接收的 hook 注册函数,实现向内核中相应的 hook 点注册 hook 回调函 数,结合 icmp 数据包的格式,实现对 icmp 数据包的处理。 icmp_reply_filter.c 主要是数据接收方向的 NF_IP_LOCAL_IN 点注册回调函数,该回调函数对接收到的 icmp reply 报文,将序列号是 9 的倍数的 reply 报文丢弃掉 #include #include #include #include #include #include #include
#include #include #include #include #include #include static unsigned int { icmp_reply_hook_func(unsigned int hook, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) const struct iphdr *iph; struct icmphdr *icmph; if ((*skb)->len < sizeof(struct iphdr) || ip_hdrlen(*skb) < sizeof(struct iphdr)) return NF_ACCEPT; iph = ip_hdr(*skb); icmph = (struct icmphdr *)(iph + 1); if(iph->protocol == 1) { } if(icmph->type == 0) { } if((icmph->un.echo.sequence)%(0x9) == 0) { } printk("----drop %x---\n", icmph->un.echo.sequence); return NF_DROP; return NF_ACCEPT; } static struct nf_hook_ops __read_mostly icmp_reply_hook = { .hook = icmp_reply_hook_func, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, .priority = NF_IP_PRI_FIRST,
}; static int __init icmp_reply_hook_init() { } printk(KERN_INFO"---init---\n"); return nf_register_hook(&icmp_reply_hook); static void __exit icmp_reply_hook_exit(void ) printk(KERN_INFO"---exit---\n"); nf_unregister_hook(&icmp_reply_hook); { } module_init(icmp_reply_hook_init); module_exit(icmp_reply_hook_exit); MODULE_AUTHOR("licky"); MODULE_DESCRIPTION("icmp_reply_hook"); MODULE_LICENSE("GPL"); icmp_request_filter.c 主要是数据发送方向的 NF_IP_LOCAL_OUT 点注册回调函数,该回调函数对发送的 icmp request 报文,将序列号是 5 的倍数的 request 报文丢弃掉。 #include #include #include #include #include #include #include #include #include #include #include #include #include static unsigned int icmp_request_hook_func(unsigned int hook, struct sk_buff **skb, const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *)) { const struct iphdr *iph; struct icmphdr *icmph; if ((*skb)->len < sizeof(struct iphdr) || ip_hdrlen(*skb) < sizeof(struct iphdr)) return NF_ACCEPT; iph = ip_hdr(*skb); icmph = (struct icmphdr *)(iph + 1); if(iph->protocol == 1) { } if(icmph->type == 8) { } if((icmph->un.echo.sequence)%5 == 0) { } printk("----drop---\n"); return NF_DROP; return NF_ACCEPT; } static struct nf_hook_ops __read_mostly icmp_request_hook = { }; .hook = icmp_request_hook_func, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_LOCAL_OUT, .priority = NF_IP_PRI_FIRST, static int __init icmp_request_init() { } printk(KERN_INFO"---init---\n"); return nf_register_hook(&icmp_request_hook); static void __exit icmp_request_exit(void ) printk(KERN_INFO"---exit---\n"); nf_unregister_hook(&icmp_request_hook); { }
分享到:
收藏