网桥调用IP层netfilter的HOOK函数

2023-12-19 10:58

本文主要是介绍网桥调用IP层netfilter的HOOK函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Linux中的网桥属于二层转发设备,可利用ebtables工具根据数据包的ethernet头等信息,配置规则,如下,将目的MAC地址为00:01:02:03:04:05的数据包,转发到目的MAC地址为00:06:07:08:09:0a的主机上:

ebtables -t nat -A PREROUTING -d 00:01:02:03:04:05 -j dnat --to-destination 00:06:07:08:09:0a

但是,网桥不仅可以支持ebtables配置的二层规则,也可支持iptables配置的三层规则。可通过PROC文件系统实现动态控制,控制文件位于/proc/sys/net/bridge目录下的bridge-nf-call-iptables和bridge-nf-call-ip6tables。


初始化

内核中网桥代码,通过调用br_netfilter_init函数,注册二层netfilter的三个hook点,分别是NF_BR_PRE_ROUTING,NF_BR_FORWARD和NF_BR_POST_ROUTING。这三个hook点,分别对应了三层netfilter的三个相同的hook点(准确说,是三层的6个hook点,IPv4与IPv6各三个点),这样在数据包经过网桥的这三个hook点时,就可以调用三层的iptables规则了。

三层netfilter的另外两个hook,NF_INET_LOCAL_IN和NF_INET_LOCAL_OUT,为发往主机和从主机发出的数据包所经过的hook,其本身自会经过三层协议栈的处理而被调用到,不需要在二层网桥上调用。


static struct nf_hook_ops br_nf_ops[] __read_mostly = {{.hook = br_nf_pre_routing,.pf = NFPROTO_BRIDGE,.hooknum = NF_BR_PRE_ROUTING,},{.hook = br_nf_forward_ip,.pf = NFPROTO_BRIDGE,.hooknum = NF_BR_FORWARD,},{.hook = br_nf_post_routing,.pf = NFPROTO_BRIDGE,.hooknum = NF_BR_POST_ROUTING,},
}static int __init br_netfilter_init(void)
{ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
}


网桥PRE_ROUTING HOOK

数据包在进入网桥(br_handle_frame)后,调用其NF_BR_PRE_ROUTING hook点上注册的函数。其中,会调用到之前注册的br_nf_pre_routing函数。其首先检查proc文件bridge-nf-call-iptables是否允许数据包到达三层netfilter的hook点。之后调用setup_pre_routing函数准备调用NF_INET_PRE_ROUTING hook点注册的函数,两点准备工作:第一skb中pkt_type需要由PACKET_OTHERHOST修改为PACKET_HOST,否则将会被三层丢弃;第二skb中的dev由物理口设备修改为其父设备(网桥设备),因为像REDIRECT等的iptables规则需要使用设备的IP地址(子设备无三层地址),所以作此修改。注意,最后在br_nf_pre_routing_finish函数中,会将此两项修改还原回去。

IPv6相关的NF_INET_PRE_ROUTING调用也在br_nf_pre_routing函数中处理,此处略去。


struct net_device *setup_pre_routing(struct sk_buff *skb)
{if (skb->pkt_type == PACKET_OTHERHOST) {skb->pkt_type = PACKET_HOST;nf_bridge->pkt_otherhost = true;}nf_bridge->physindev = skb->dev;skb->dev = brnf_get_logical_dev(skb, skb->dev);
}static unsigned int br_nf_pre_routing(...)
{if (!brnf_call_iptables && !br->nf_call_iptables)return NF_ACCEPT;if (!setup_pre_routing(skb))return NF_DROP;NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->sk, skb, skb->dev, NULL,br_nf_pre_routing_finish);
}


网桥转发HOOK


在网桥转发(NF_BR_FORWARD)hook点上,除了要修改skb的pkt_type到PACKET_HOST外,还要在调用三层NF_INET_FORWARD hook点函数之前,将入口设备和出口设备修改为对应的父设备(网桥设备)。skb成员dev中指向的为真实的出口设备(非网桥)。最后br_nf_forward_finish函数会还原skb->pkt_type的值。

另外,只有PROC文件bridge-nf-call-iptables为真,nf_bridge才会在br_nf_pre_routing函数中分配,此时检查nf_bridge就可以了。


static unsigned int br_nf_forward_ip(...)
{if (!skb->nf_bridge)return NF_ACCEPT;parent = bridge_parent(state->out);if (!parent)return NF_DROP;if (skb->pkt_type == PACKET_OTHERHOST) {skb->pkt_type = PACKET_HOST;nf_bridge->pkt_otherhost = true;}NF_HOOK(pf, NF_INET_FORWARD, NULL, skb,brnf_get_logical_dev(skb, state->in), parent, br_nf_forward_finish);
}


网桥POST_ROUTING


网桥的NF_BR_POST_ROUTING hook点调用三层的NF_INET_POST_ROUTING hook点,但与前两个HOOK点不同,主机本身发出的报文也会调用NF_INET_POST_ROUTING hook点的函数,所以需要再此判断physoutdev是否为空,为空说明主机已经在IP三层处理中调用了此hook点,直接返回NF_ACCEPT。


static unsigned int br_nf_post_routing(...)
{if (!nf_bridge || !nf_bridge->physoutdev)return NF_ACCEPT;if (skb->pkt_type == PACKET_OTHERHOST) {skb->pkt_type = PACKET_HOST;nf_bridge->pkt_otherhost = true;}NF_HOOK(pf, NF_INET_POST_ROUTING, state->sk, skb,NULL, realoutdev, br_nf_dev_queue_xmit);
}

内核版本

linux-3.10.0



这篇关于网桥调用IP层netfilter的HOOK函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511913

相关文章

golang panic 函数用法示例详解

《golangpanic函数用法示例详解》在Go语言中,panic用于触发不可恢复的错误,终止函数执行并逐层向上触发defer,最终若未被recover捕获,程序会崩溃,recover用于在def... 目录1. panic 的作用2. 基本用法3. recover 的使用规则4. 错误处理建议5. 常见错

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Ubuntu固定虚拟机ip地址的方法教程

《Ubuntu固定虚拟机ip地址的方法教程》本文详细介绍了如何在Ubuntu虚拟机中固定IP地址,包括检查和编辑`/etc/apt/sources.list`文件、更新网络配置文件以及使用Networ... 1、由于虚拟机网络是桥接,所以ip地址会不停地变化,接下来我们就讲述ip如何固定 2、如果apt安

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

一分钟带你上手Python调用DeepSeek的API

《一分钟带你上手Python调用DeepSeek的API》最近DeepSeek非常火,作为一枚对前言技术非常关注的程序员来说,自然都想对接DeepSeek的API来体验一把,下面小编就来为大家介绍一下... 目录前言免费体验API-Key申请首次调用API基本概念最小单元推理模型智能体自定义界面总结前言最

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE