ebtables之BROUTING和PREROUTING的redirect的区别

ebtables和iptables实用工具都使用了Netfilter框架,这是它们一致的一方面,然而对于这两者还真有一些需要联动的地方。很多人不明白ebtales的broute表的redirect和nat表PREROUTING的redirect的区别,其实只要记住两点即可,那就是对于相同点,它们都将数据包导向了本地的IP层;对于不同点,broute表的redirect将数据包的接收设备设置成了实际接收数据的物理网卡,而nat表将数据包的接收设备设置成了桥设备,这个可以在Linux协议栈的源代码中看个究竟。对于broute表的redirect,可以在br_handle_frame这个handle_bridge调用的回调函数中看到以下的语句:
switch (p->state) { case BR_STATE_FORWARDING:     rhook = rcu_dereference(br_should_route_hook);     if (rhook != NULL) {         if (rhook(skb))             return skb;         dest = eth_hdr(skb)->h_dest;     }     /* fall through */ case BR_STATE_LEARNING:     if (!compare_ether_addr(p->br->dev->dev_addr, dest))         skb->pkt_type = PACKET_HOST;     NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,         br_handle_frame_finish);     break; ...
我们看一下br_should_route_hook这个回调函数ebt_broute:
static int ebt_broute(struct sk_buff *skb) {     int ret;      ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL,                dev_net(skb->dev)->xt.broute_table);     if (ret == NF_DROP)         return 1; /* route it */     return 0; /* bridge it */ }
它进入了我们都熟悉xxx_do_table函数,这也就是常规的Netfilter规则查找操作,最终在找到匹配规则时,进入redirect这个target。如果没有broute表的规则,则会进入NF_HOOK这个HOOK,其间将会遍NF_BR_BROUTING所有的规则,如果有target为redirect的规则命中,则也会进入redirect这个target,这个target是什么呢?是ebt_redirect_tg这个函数:
static unsigned int ebt_redirect_tg(struct sk_buff *skb, const struct xt_target_param *par) {     const struct ebt_redirect_info *info = par->targinfo;      if (!skb_make_writable(skb, 0))         return EBT_DROP;      if (par->hooknum != NF_BR_BROUTING)         //如果是NAT的PREROUTING,则将桥的MAC地址复制到数据包的目的MAC地址。         memcpy(eth_hdr(skb)->h_dest,                par->in->br_port->br->dev->dev_addr, ETH_ALEN);     else         //如果是broute表的BROUTING,则将实际接收数据包的物理网卡的MAC地址复制到数据包的目的MAC地址。         memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);     //本机可以接收该数据包     skb->pkt_type = PACKET_HOST;     //一般返回DROP     return info->target; }
从br_handle_frame可以看出,一旦broute表的匹配规则返回了DROP,则handle_bridge直接返回这个skb,不再向下执行,这意味着skb将在handle_bridge返回后沿着netif_receive_skb继续走下去,而如果没有匹配的broute表规则,则可能在nat表的PREROUTING链中命中,然后在执行了ebt_redirect_tg之后会调用br_handle_frame_finish继续下去,在br_handle_frame_finish中,由于目的MAC地址已经改成了本机网卡的MAC地址,因此会调用br_pass_frame_up将数据包向协议栈的上层发送:
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) {     struct net_device *indev, *brdev = br->dev;      brdev->stats.rx_packets++;     brdev->stats.rx_bytes += skb->len;      indev = skb->dev;     //将skb的dev修改成了brX,这样在接下来经过LOCAL_IN之后再次调用netif_receive_skb之后,在netif_receive_skb中就不会再次进入handle_bridge的 处理逻](我家小小按下的...)辑了。     skb->dev = brdev;      NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,         netif_receive_skb); }
注意,在broute表中的redrect之后,数据包的接收设备是实际的物理网卡ethX,目的MAC成了物理网卡ethX的MAC地址,而在nat的PREROUTING的redirect之后,数据包的接收设备是网桥设备,目的MAC地址成了网桥设备的MAC地址,知道了这个之后,我们再看一下一个和iptables的nat表的redirect的问题。
    设想一个配置,本机S的eth0的IP地址为1.1.1.254/24,其上开启tcp的88端口,和本机直连的一台主机H的IP地址为1.1.1.2/24,在S上配置:
brctl addbr br0 brctl addif eth0 ifconfig br0 1.1.1.254/24 ifcongig eth0 0.0.0.0  #为了防止路由乱掉,因此删除eth0的IP地址 iptables -t nat -A PREROUTING -d 2.2.2.2 -p tcp --dport 1234 -j REDIRECT --to-ports 88
在H上执行
route add -host 2.2.2.2 gw 1.1.1.254 telnet 2.2.2.2 1234
结果呢?不通!连syn-ack都没有收到,然而在S上删除REDIRECT规则而执行以下规则则是可以的:
iptables -t nat -A PREROUTING -d 2.2.2.2 -p tcp --dport 1234 -j DNAT --to-destination 1.1.1.254:88
难道DNAT和REDIRECT有什么区别吗?如果你不明白这两者有什么区别,那么如果你知道SNAT和MASQUERADE的区别也不错,起码能帮助你理解。DNAT和SNAT能指定任
意的源地址一样,可以指定任意的目的地址,那么REDIRECT则和MASQUERADE也类似,它只是内核根据自己的策略而选择出的一个目的地址,正如MASQUERADE也是内
核根据RFC的建议以及自己的策略选择出的一个源地址一样。那么如何来选择REDIRECT的目的地址呢?看一下iptables的man手册就知道了:
REDIRECT

This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only called from those 
chains. It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface (locally
-generated packets are mapped to the 127.0.0.1 address). 
特别要注意的是“to the primary address of the incoming interface”这一句。内核中的REDIRECT规则是如何做到这点的呢?这还要看一下代码才知道:
static unsigned int redirect_tg(struct sk_buff *skb, const struct xt_target_param *par) {     ...     if (par->hooknum == NF_INET_LOCAL_OUT)         newdst = htonl(0x7F000001);     else {         struct in_device *indev;         struct in_ifaddr *ifa;          newdst = 0;          rcu_read_lock();         indev = __in_dev_get_rcu(skb->dev);         //取出接收设备的IP地址         if (indev && (ifa = indev->ifa_list))             newdst = ifa->ifa_local;         rcu_read_unlock();         //如果接收设备没有IP地址,则丢弃数据包         if (!newdst)             return NF_DROP;     }     ...     return nf_nat_setup_info(ct, &newrange, IP_NAT_MANIP_DST); }
这下我们就一切都明白了,既然broute表的redirect将接收设备设置为实际的物理网卡,而此网卡的IP地址已经被删除,那么上述函数的newdst当然不存在了,因此数据包就被DROP掉了,到此为止,问题就很清晰了。可见ebtables的redirect方式直接影响到了iptables的redirect,为了让iptables的redirect在使用bridge时仍然随时可行,则必须为使能broute redirect的网卡上设置IP地址,为了不使路由冲突,考虑127.0.0.2...
注:broute表的意义

为何会有这样的问题?broute是原因。所谓的broute则是bridge or router,类似早先安装宽带时运营商送的那种猫,能作为桥设备也能作为路由器。如果作为路由器,根本不存在桥设备这一说,因此将接收设备设置为实际的物理网卡也是理所当然的啦。



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1269005

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LVS的四种模式的实现

LVS 是四层负载均衡,也就是说建立在 OSI 模型的第四层——传输层之上,传输层上有我们熟悉的 TCP/UDP,LVS 支持 TCP/UDP 的负载均衡。LVS 的转发主要通过修改 IP 地址(NAT 模式,分为源地址修改 SNAT 和目标地址修改 DNA…

MyISAM与InnoDB两者之间区别与选择,详细总结,性能对比

1、MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,而且不支持外键,如果执行大量的sel…

leetcode557. 反转字符串中的单词 III

给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 示例: 输入:“Let’s take LeetCode contest” 输出:“s’teL ekat edoCteeL tsetnoc” 代码 class Solution {public St…

linux命令数据盘分多个区,pvmove命令 – 移动物理盘区

pvmove命令的作用是可以将源物理卷上的物理盘区移动到一个或多个其他的目标物理卷。使用pvmove命令时可以指定一个源日志或卷。在这种情况下,只有逻辑卷使用的区才会被移动到目标物理卷上的空闲或指定的区。如果没有指定的物理卷,则使用卷组的默认规则分…

spanning-tree extend system-id

spanning-tree extend system-id 在交换机上启用extended-system ID 特征使其支持 1024 MAC 地址, 在全局模式下使用 spanning-tree extend system-id命令.禁用时前面加 no。 spanning-tree extend system-id no spanning-tree extend system-id 命令用法 在不提供 1024 MAC 地…

leetcode841. 钥匙和房间(bfs)

有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,…,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。 在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i]&a…

Codeforces 235C Cyclical Quest (后缀自动机)

题目链接: https://codeforces.com/contest/235/problem/C 题解: 对大串建后缀自动机 对询问串复制拆环。这里一定要注意是复制一个循环节不是复制整个串!循环节是要整除的那种 然后要做的实际上是在大串上跑,每经过一个点求出当前的最长公共子串&#x…

泛型型协变逆变_Java泛型类型简介:协变和逆变

泛型型协变逆变by Fabian Terh由Fabian Terh Java泛型类型简介:协变和逆变 (An introduction to generic types in Java: covariance and contravariance) 种类 (Types) Java is a statically typed language, which means you must first declare a variable and …

安卓系统换成linux系统软件,将旧安卓手机打造成“简易linux”机器,并部署AdGuardHome...

从原教程的安装Linux Deploy 完成后,在配置 Linux下载镜像的一些东西时有些许出入。首先,我是用的下载源地址是 http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports 清华的源挺好用的。 其他有出入的配置如图(记得把源地址改清华的,华中科大…

let与expr命令的用法与实战案例

let命令的用法 格式: let 赋值表达式 【注】let赋值表达式功能等同于:(赋值表达式) 例子:给自变量i加8 12345678[rootXCN ~]# i2 [rootXCN ~]# let ii8 [rootXCN ~]# echo $i 10[rootXCN ~]# ii8 #去掉let定义 [root…

在使用ToolBar + AppBarLayout,实现上划隐藏Toolbar功能,遇到了一个坑。

问题:Android5.0以下版本Toolbar不显示沉浸式状态栏,没有这个问题,但是5.0以上版本,就出现了莫名其妙的阴影问题,很是头疼。 分享一下我的解决方案: 在AppBarLayout中加一个属性: app:elevation…

leetcode1476. 子矩形查询

请你实现一个类 SubrectangleQueries ,它的构造函数的参数是一个 rows x cols 的矩形(这里用整数矩阵表示),并支持以下两种操作: updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) 用 new…

msbuild构建步骤_如何按照以下步骤构建最终的AI聊天机器人

msbuild构建步骤by Paul Pinard保罗皮纳德(Paul Pinard) 如何按照以下步骤构建最终的AI聊天机器人 (How to build the ultimate AI chatbot by following these steps) 快速指南,可帮助您避免常见的陷阱 (A quick guide that helps you avoid common pitfalls) Bui…

第一章:最小可行区块链

概览区块数据结构区块哈希创世块创建区块保存区块链验证区块完整性选择最长链节点间通信操作节点架构运行测试小结概览 区块链的基础概念非常简单, 说白了就是一个维护着一个持续增长的有序数据记录列表的这么一个分布式数据库。在此章节中我们将实现一个简单的玩具版的区块链。…

Oracle Controlfile控制文件中记录的信息片段sections

初学Oracle的朋友肯定对Controlfile控制文件中到底记录了何种的信息记录而感到好奇,实际上我们可以通过一个视图v$controlfile_record_section来了解控制文件的信息片段: SQL> select type, record_size, records_total from v$controlfile_record_s…

linux 怎么禁止遍历目录,linux下遍历目录功能实现

/*编译:dir:dir.cgcc -o $ $<*/#include #include #include #include #include int do_search_dir(char *path);int do_check_dir(char *fullpath, char* truefullpath);void usage(char *apps);int count 0;intmain(int argc,char **argv){char fullpath[…

leetcode面试题 16.26. 计算器(栈)

给定一个包含正整数、加()、减(-)、乘(*)、除(/)的算数表达式(括号除外)&#xff0c;计算其结果。 表达式仅包含非负整数&#xff0c;&#xff0c; - &#xff0c;*&#xff0c;/ 四种运算符和空格 。 整数除法仅保留整数部分。 示例 1: 输入: “32*2” 输出: 7 代码 clas…

团队项目电梯会议视频

http://v.youku.com/v_show/id_XMjcyMjI3Mjk2NA.html?spma2hzp.8244740.userfeed.5!2~5~5~5!3~5~A转载于:https://www.cnblogs.com/jingxiaopu/p/6749776.html

arduino服务器_如何使用Arduino检查Web服务器的响应状态

arduino服务器by Harshita Arora通过Harshita Arora 如何使用Arduino检查Web服务器的响应状态 (How to use Arduino to check your web server’s response status) Last year, I created Crypto Price Tracker (an app which was acquired by Redwood City Ventures this yea…

leetcode486. 预测赢家(dp)

给定一个表示分数的非负整数数组。 玩家 1 从数组任意一端拿取一个分数&#xff0c;随后玩家 2 继续从剩余数组任意一端拿取分数&#xff0c;然后玩家 1 拿&#xff0c;…… 。每次一个玩家只能拿取一个分数&#xff0c;分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束…