Linux net namespace的另类玩法

作为一个手艺人,像下面写的这么玩才看上去像个匠人。能手工完成的就不用工具。一个问题有了一种解决问题的方法后,还要再想个更麻烦的方法。

本来想周末写下来的,可是周末事情排的很满,只好压缩工作日的时间了,因此,行文可能便不会那般流水,但是意思确实达到了。


你能想象通过网络远程登录到一台Linux机器后,却发现没有任何网卡,没有一条路由吗?

先来一个感观上的认识:
在这里插入图片描述
是不是很神奇呢?

明明是通过网络登录进系统的,进去以后却看不到任何网络配置信息。是的,没有网卡,没有路由,什么都没有。

怎么做到的呢?

周三晚上加班,回家的路上,在溪上玫瑰园会所发了一则朋友圈:

ifconfig -a查不到任何网卡信息,route查不到任何路由信息,任何命令查不到任何网络信息,然后却能和外网通信…
别问我是怎么做到的,周末揭晓!

这是无意中发现的沙盒,实际上就是把net ns给隐藏了,既然root可以从docker逃出来,那外面怎么就不能躲进去呢。
来吧,躲进去后一锅端,把容器销毁,网络也就彻底隐藏了。
专为不懂网络却爱瞎折腾嘚瑟装逼的编程者准备的沙盒,让你瞎配置网络,配毛线啊。
哈哈

是的,就是先创建一个空的netns(不添加任何网卡的netns),然后将该netns指派给1号systemd进程的netns即可,我们知道,在默认情况下,1号进程衍生出来的进程树是不带CLONE_NEWNS来clone的,也就是说所有的进程的netns和1号进程是共享的,所以一下子就把系统所有的进程都关进去了…

我们先看看如何做到,先创建netns:

[root@localhost ~]# ip netns add jail

然后为该netns指派一个bash进程,用于获取该netns的内存地址:

[root@localhost ~]# ip netns exec jail bash
# 该bash进程的PID为1782.

然后开始修改1号进程的netns:
在这里插入图片描述

效果就是下面的样子:
在这里插入图片描述
上图红色框之前是写1号进程的netns之前,网络配置正常,红色框之后乃写入之后,网络配置消失。

是不是很有意思呢?


接下来我们来看下为什么网络配置没有了,还能从外面连入。

事实上,netns是一个容器,里面有网卡,路由表,iptables规则等,数据包从网卡上来后,其netns就是网卡隶属的netns,显然,init_net只是和系统的进程们解绑,它并没有消失,因此enp0s3网卡依然属于init_net这个初始netns,在整个协议栈处理的过程中,netns取的就是网卡的netns:

return inet_lookup(dev_net(skb_dst(skb)->dev), ...

该取自dev的netns最终会附着在socket上。所以,主动进来数据包处理和进程的netns无关,而只和网卡的netns有关。

当然,如果是本机主动往外发包,就发不出去了,因为所有进程绑定的netns是一个空的netns,没有路由表,没有网卡…

这就解释了为什么从外面还能连进去。同时也指引了一条明路,告诉人们这个模式还是有用的:

  • 业务程序员不需要查看或者配置网络,对他们隐藏这些底层网络信息是有好处的,系统的问题不用他们操心,他们才能好好编程。嗯,把程序员关进笼子

注意,不要误会,我不是针对程序员,我是针对网吧的网管,在我的朋友圈下面,我自己回复如下:

我记得之前在网吧查资料,当我打开命令提示符,不可一世的网管就过来一顿快捷键给我关了。其实网管算个球啊,在不懂的人面前耍一下罢了,我这不也可以在编程的面前耍一下了吗?然而我还是想让人人都能这么耍一下,把系统玩坏,并教人把系统玩坏,是我们手艺人的终极目标

业务程序员从外部登录到隐藏了网络的开发机,开始专心编写业务逻辑。也许你会说,他们也能用crash命令把netns改回去啊,init_net很容易查找到:
在这里插入图片描述
然而,应该很少有写业务代码的程序员拥有这个能力和基础知识认知。


OK,现在,如果我们想重新配置网络,怎么办呢?

很简单,在jail里运行一个bash,然后将该bash的netns改回init_net即可,虽然可以在jail运行任意bash以修改其netns为init_net,但我们依然以刚才的1782号进程为例,修改完成后,在该bash就能重新看到网络配置了:
在这里插入图片描述

如果你不想每次都这么麻烦,你可以将init_net藏在jail netns里的一个 不太容易被关注且永不退出 的进程里,即将init_net的地址填写在该进程nsproxy的net_ns里,然后使用nsenter命令即可进入。

我们依然以jail中的1782号bash进程为例,现在我们知道,1782号bash进程的netns已经是init_net了,于是,我们可以这么做:
在这里插入图片描述
可以看到,nsenter之前,网络配置什么都没有,nsenter到1782号进程的init_net之后,网络配置重新可见。

netns真是个好东西,它既是网络组件的容器,又是nsproxy的元素,而这整个套件就是容器的基础。详情参见network_namespaces的manual。

实在太好玩,Linux要被玩坏。

最后,值得注意的是,以上所有用crash命令可以完成的事情,都可以通过映射读写/dev/mem来完成。我前面已经写过了,不再赘述。不好意思的是,本文中我使用了crash工具,而不是像手艺人一样手改/dev/mem来hack…


浙江温州皮鞋湿,下雨进水不会胖。

发布了1545 篇原创文章 · 获赞 4728 · 访问量 1055万+

猜你喜欢

转载自blog.csdn.net/dog250/article/details/103182447
今日推荐