一个关于Linux Bridge配置的吐嘈

话说有些事情十分适合在放假前的一天折腾一天,但绝对不适合在你准备去吃饭前多看一眼...我上周就碰到了这么一件揪心的事,终于以低血糖收场。十分狼狈地四处觅食,却觅到了一包超级辣的鸡爪。吃完后感觉症状加重了。于是向邻座的同事乞讨了巧克力糖。唉...这一切起源于我在准备吃午饭前一头扎进了一个技术问题,本以为能靠配置搞定,终于却还是不得不以改动The Fxxxing code告终!事情起源于公司的一个禁令:禁止上外网!

禁止工作时间上外网,碰到问题就仅仅能拖着。多么奇葩的行政管理策略。

事实上。想在工作期间上外网一般有三个办法:
1.假设看直播之类的,能够躲在厕所里蹲着看,没人知道你在看什么。代价就是3G流量和麻醉状态的腿和脚;
2.填一张签报单,说明自己上网的理由。比方查资料之类非常笼统但却没有漏洞的理由,然后找领导签字,一般都会批准的。然后你就能够在查资料之余顺便看看新闻。天气预报之类的。
3.原自公司网络管理的漏洞,仅仅封掉了熟知port,有些port却开着,假设你在家里开一台Linux机器,那么就能够通过家里的机器上网了。
以上3点中,第1点基本不可能了。由于自公司搬家以后,厕所就一点信号都没有了。别说上网,万一没带纸都是非常麻烦的事。第二点大家都会做,也确实这么做了,结果公司禁令的最大效果就是各种打印。各种签字,各种跑,可是技术人员不满足于这样的非技术的解决方案。于是一定要尝试一下第3种方式。

一般而言。家庭网络的拓扑都是在最外面有一个无线路由器,然后里面几个设备,PC,各种PAD,手机之类的。PC逐渐不再流行了。是守旧的思想在促使非常多人一定要买或者组装高大上的PC,就像10年前非常多人钟情于眼下差点儿已经绝迹的大型机一样。在这个后终端时代。买一块能够载有Linux的小板子或许是个不错的主意,它耗电少,无噪音,小型,随便塞在哪里都能够,长期开机也无所谓,它是做家庭上网代理的最好选择了。

同事买了一块这样的小板子,据说非常不错。如今想在公司的时候也能通过家里的那个小设备上网,须要做些什么呢?非常显然,造一个IPIP或者GRE隧道是不错的选择,可是假设想加密的话,就必定要用某种VPN技术。那么首选的是OpenVPN,由于相比IPSec而言。我们有现成的配置。

然而OpenVPN參数太多,也麻烦,于是想到了用simpletun。一个差点儿仅仅是用来学习的,超级小的,根本称不上项目的小东西,尽管它没有加密功能。可是为它增加一个base64编码支持还是easy的...于是就选择用simpletun建立隧道。
       simpletun本身一点问题都没有。非常easy就把隧道建立了,家里的作为服务端,公司的作为client,由于公司防火墙仅仅让主动出不让主动进。那么还有什么问题吗?问题来了。

用tun模式还是tap模式呢?我比較倾向于tap模式,由于这样就能够把家里的局域网bridge到公司了,公司的机器和家里的小设备以及家里的路由器在一个网段,多好!可是这须要做两个额外的工作:
1.把家里小设备的物理网卡eth0和simpletun启动的虚拟网卡tap0用brctl命令做成一个网桥,然后让这个网桥接管原来eth0上的IP地址,
2.假设公司的机器连接家里的小设备成功。那么其simpletun的虚拟网卡地址也要配置成和家里局域网同一个网段的。
以上第2个问题非常好解决。难的是第1个。

要知道,对家里小设备的操作是远程SSH上去的。数据包通过家里路由器的公网IP连接,之后被路由器DNAT到小设备的eth0的IP地址,这就意味着在网桥设置期间。必须保证这个IP地址的连通性,可是眼下的Linux Bridge机制是不能支持的。
       通观上述过程,事实上和虚拟网卡没有关系。于是能够把整个问题转化为:设eth0上有一个IP,为ip。怎样找一个办法,使这个ip在下列过程中始终保持连通性,该过程为,将eth0增加一个新创建的网桥。

整个问题中,关键的操作有两点。例如以下所看到的:
1.网桥起来的那一刻。
2.把eth0增加到网桥的那一刻;
有一点是毋庸置疑的,那就是仅仅要你把eth0增加到网桥。假设eth0收到数据包,内核会认为该数据包是网桥接收的而不再是eth0接收的,包含ARP Reply在内,于是系统的arp表中本来拥有的路由器的arp项:
192.168.1.1 00:11:22:33:44:55 eth0
就会变成:
192.168.1.1 00:11:22:33:44:55 br0 或者 192.168.1.1 (incomplete)  br0(假设br0还没有up的情况下)
要想数据通信能完毕,路由结果项的邻居dev字段必须和arp表项的邻居dev字段一致。这也是二层,三层之间的一个一致性渠道。换句话说。要想保持IP的连通性,必须要在将eth0增加网桥的那一刻同一时候改变路由,而这是不可能的,由于brctl addif操作仅仅完毕一件事,即将eth0增加br0!
       假设换一个思路。即先将路由生效。然后再加eth0到br0呢?同样的问题,路由项的dev改变为br0了。然而此时arp项的dev还是eth0!

总之就是路由项的dev和arp项的dev在网桥的操作序列中总是会有一个操作导致其不一致。而这一刻的不一致将导致断网,兴许的操作将无法完毕,就算是一旦不一致了,仅仅能靠还有一个配置使其一致,它自己并不会收敛成一致状态。

其本质原因有两点:1.brctl以及route操作都是原子的,二者互不牵连;2.网桥没有一个中间过渡状态。解决问题就是要么将brctl和route关联起来,要么引入一个中间状态。想想就知道。关联brctl和route肯定是不好的,毕竟我们这个需求不是一个普遍的需求,也有非常多办法能够解决它,比方设置一个开机if-up脚本。或者写一个批处理后台运行。之所以这么较真儿非要来个online作业是由于我一直都以为自己能解决全部的网络问题...于是就决定用另外一种方式,引入一个中间状态,将多个互不相关的触发机制合并为单一的触发,比方尽管调用了addif将eth0增加了br0,调用ifconfig为br0设置了IP地址。可是在那个单一的触发动作没有运行前,一切都不生效。显而易见的做法是,假设br0没有up,则即使eth0增加了br0还依旧使用eth0进行数据通信。找到要改动的代码非常easy,由于Linux网桥的代码本身就非常easy,改动net/bridge/br_input.c的br_handle_frame函数:

struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
{
const unsigned char *dest = eth_hdr(skb)->h_dest;
int (*rhook)(struct sk_buff *skb); ////////增加下面代码
int flags = p->br->dev->flags;
if (!(flags & IFF_UP)) {
return skb;
}
////////
.....
}

然后载入改动后的模块后运行下面序列:
1.新增网桥
brctl addbr br0
2.关闭STP(可选)
brctl stp br0 off
3.设置一个掩码稍长的IP,临时设置为down状态
ifconfig br0 192.168.1.100/25 down
4.增加eth0到br0
brctl addif br0 eth0
5.开启br0
ifconfig br0 up
6.清除eth0的IP
ifconfig eth0 0.0.0.0
值得一提的是上面第3个步骤。Linux中假设不同语义的同样路由是增加到一个list的尾部的,因此假设两块网卡配置同样的IP地址,则谁先up谁的链路路由在前面优先被匹配,设置掩码稍长的IP地址是为了让br0的网段比eth0的网段更加精确,但要注意。默认网关一定不能被25位掩码和br0的IP劈开到不同的网段。比方默认网关是192.168.1.128后面的地址就不能,由于它已经和192.168.1.100不在一个网段了。假设实在想使用稍长掩码的IP地址。你就要增加一个force onlink的路由。事实上能够用metric来做到上面的说的而不用稍长掩码的IP地址,也能够改动Linux内核的路由部分,将fn_hash_insert中的某处list_add_tail改为list_add_head(此处不说了。感兴趣的自行改动)...
       事情就这样攻克了。可是却无法落实!什么叫落实呢?就是说形成一个通用的方案。我想假设我把改动后的bridge机制提交给kernel maillist,肯定会有非常多人骂的,更有可能的是根本没人搭理我...从代码风格上,这样的硬编码方式不可取。从实际效果来看,你不能保证使用bridge的人一定就允许你的逻辑,因此做成可选的选项就比較好,怎么个可选法呢?模块參数当然是其一,可是还有更好的方法。

行文至此,有一个疑问,为何不用ebtables的broute表呢?比方你设置一条:
ebtables -t broute -A BROUTING -j DROP
这条命令的效果和上面改动代码的效果一样,可是问题又来了,当你运行brctl addif br0 eth0的时候,就会断网。由于此时你须要删掉那个规则。然而已经没有机会删除了,由于你再也连不上去了。实际上。这也是单一触发的问题。每次操作仅仅触发一个动作。和上面讨论的问题实质是一样的。

之所以在本文快要结束的时候引入一个新的问题,是为了展示一个更好的方案。

我们来看看上面的ebtable命令缺了什么,缺乏的正是一个match。即对br0状态的推断,它才会一股脑地将全部的数据都DROP到上层,假设它成为下面这样子的话:
ebtables -t broute -A BROUTING -i br0 -state --dev-state up -j DROP
那岂不就完美了。丝毫不用改现有的Linux Bridge逻辑,须要做的仅仅是增加一个ebtables的match模块,这样的模块化的东西本来就是让扩展的,至于怎么扩展,就看ebtables有没有iptables灵活了,好像是没有,因此我也就在此作罢了。
       这明显不是什么吐嘈。纯粹是自己比較无聊而写的一篇技术指南。

随便吧!让人吐嘈的不是这篇文章所表达的内容。而是我对信息记录的极大不满,因此,真正的吐嘈这才真正開始。
       我越发认为使用智能手机是多么危急的一件事。昨晚被老婆查手机,查完后怒了,不是针对老婆。而是针对没天理的APP。我以前去过哪里,在那个地方待了多长时间,通过坑爹的iPhone隐私都能够查到,通过还有一个APP。就能够查到以前全部的通话记录,短信。都上过哪些站点。而最令人气愤的是,你删除的东西可能不是真的被删除,依旧留在机器的某个角落。比方/var/cache/...我说一个详细的困境吧,假设你用iPhone下载了新浪微博,用一个帐号登录了。然后退出,这个账号就永远存在于你的手机了。下次,你仅仅要输入账号的第一位,就会自己主动补全,好吧。你找不到不论什么地方能够删除这个登录信息。那么怎么办?直接将程序删除,然后又一次下载。这下清静了。不能自己主动补全了,看似清除了登录信息。好吧,是的,真的清除了。这个时候不要登录,等待,等待,然后突然收到一条那个登录过账号的特别关注好友的一条新微博。天啊。我还没登录呐,怎么就知道那条微博要推给我啊...以上是一个真实的事实。我有益这么測试过。
       微信也有问题。我把一个不宜公开的基友拉到了朋友圈黑名单。然后再把他删除,可是他的更新我还是能够看到。诸如此类的还有非常多,感兴趣的自己去玩吧。别跟我说技术不成熟导致的问题,在我看来技术永远都不可能成熟!技术至上的观点多么天真,对于仅仅懂技术或者对生活中的其他事情不关心不理解的人,一不小心就被他人引入一个万劫不复的深渊,深不知深究此事是多么的无聊。事实上非常easy,你自己做一个坏东西让别人折腾去呗。都别人玩儿又不犯法。

你要知道。全部的好点子都不是技术人员搞出来的,都TMD是小丑引申的。

留声机刚发明的初衷并非记录音乐,甚至认为记录音乐是*了这个该死却又伟大的发明。可是事实呢?
       当你走在街上,大量的摄像头指着你,就像有狙击手在暗处瞄准你却不开枪给你带来的感觉一样。由于一旦他开枪。一瞬间你就不会有不论什么感觉了。在货梯旁边的楼道吸烟的时候,可能保安正盯着你看你在通过手机看什么内容。假设你看的是禁网,他们也会受惠。

银行的流水帐单会告诉别人你在什么时间什么地点在哪家店消费了多少钱,假设你狡辩说你在*商场的经纬度地点买了一斤猪肉,那你肯定在说谎,由于你根本不知道注冊的信息有哪些。门户站点。iPhone。公司的NAS,它们都会记录你的信息,你也不知道这些信息终于会被怎样处理。最简单的办法就是TMD少进行信息交流,尽管我不会上公司不让上的站点,但我也同一时候拒绝了使用google查阅正规的技术内容,我拒绝使用互联网,仅此而已,尽管我不会去东莞,也不会跟陌生女人通话,但我还是删除了全部的通信录和APP,我拒绝使用智能手机,仅此而已。
       闭上眼睛,在厕所撒尿和在人民广场马路中心撒尿,对于没有心智的人而言是一样,可是处在时刻被监控状态的网民,实质上和闭上眼睛在广场中心撒尿没有什么两样。

对于少数技术人员而言,总是能够在撒尿的时候罩上一块简单的屏障,甚至直接睁着眼撒尿就可以,同一时候还向四周竖起了中指,但对于大多数技术人员而言,为了撒尿。却仅仅知道自己憋着尿盖一座厕所,假设你想如厕,旁边商场里就有啊。无知导致滞后...

上一篇:循序渐进之Spring AOP(1) - 原理


下一篇:skopeo---github简单记录