测试demo在:http://www.hackernel.com/jslinux/
本文代码在:https://github.com/killinux/jslinux-tap
2011年很火的jslinux,把linux跑在浏览器上,10年过去了,还有人记得这个么?
fabrice bellard官网是: https://bellard.org/jslinux 这个已经变成wasm的版本,代码不可读,所以目前这个纯js版的作为学习Linux内核的教程还是很好的。
没混淆的jslinux参考: https://github.com/levskaya/jslinux-deobfuscated
这个没有网络,硬盘也没这么大,但是代码可读。
我修改了哪些:
1.增加了硬盘部分:
硬盘在hao下面,如果想修改硬盘内容,或生成rootfs 参考 修改jslinux硬盘内容
理论上如果用indexeddb作为硬盘,硬盘应该可以更大,后续计划把browserfs加上。
2.增加了网络部分:通过websocket作为server,浏览器中linux的tap设备与服务器端通信,这个地方需要改内核编译的配置,内核的config选项一定要把TUN=yes
网络为三个部分: (1)jslinux内部网络是建立tap设备,和/dev/ttyS1设备交互,这是jslinux和浏览器交互的部分 ,类似/dev/clipboard 和浏览器上的textare交互 ,建立tap设备的代码为 [tap代码链接](https://www.iteye.com/blog/haoningabc-2436305) (2)浏览器和server用websocket链接 (3)server端linux也是同样原理,建立一个桥,tap设备一端绑在桥上,一端连在websocket上
把代码运行起来:
运行方法: 1、安装依赖,mod_pywebsocket 和bridge-utils:
cd jslinux/websocketstuntap
yum install python-virtualenv -y
virtualenv mysite
source mysite/bin/activate
pip install mod_pywebsocket
yum install bridge-utils -y
brctl show
具体参考脚本:launch.sh 注意设置 MASQUERADE 和 ip_forward=1 的转发,否则网络可能会不通
2.启动 websocketstuntap 的websocket服务:这个服务生成tap设备和websocket的关联,并把tap设备都挂在br1桥上,是jslinux之间互相通信的基础
brctl addbr br1
brctl stp br1 on
ip link set br1 promisc on
ip link set br1 up
ifconfig br1 hw ether ee:ee:ee:ee:ee:50
需要指定mac地址,否则每次新建tap这个mac会变成最新的,影响网络交互
ifconfig br1 10.0.2.1 netmask 255.0.0.0 up
3.修改websocket客户端 代码在:jslinux-tap/js/network-websockets.js 中的WebSocket server 修改成刚建立的websocket服务
4.启动两个chrome页面,注意不要在一个tab里面
在jslinux里面输入命令 cat /dev/clipboard |sh
这里是在jslinux内部建立tap设备,并通过 PCEmulator.js的serial2 调用network-websockets.js 的websocket进行交互
jslinux里面的tap设备建立:
stty -F /dev/ttyS1 -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl -ixon -opost -echo -echonl -icanon -isig -iexten -parenb cs8
./tapper --tapper-headers --ip-address 10.0.2.0 --netmask 255.255.255.0 --randomize-ip /dev/ttyS1 /dev/ttyS1 &
主要原理是
jslinux:/dev/ttyS1
----->
jslinux:tap0
----->
PCEmulator.js:serial2(0x2f8)
----->
network-websockets.js:websocket client
----->
python:tap_wsh.py:websocket server
----->
linux tap:websockettunt0
----->
linux桥:br1
通过桥实现多个jslinux的互通:
/dev/ttyS1 对应 com口,序列号 0x2f8
参考:google定义的设备号
jslinux 网络驱动:
dmesg |grep ttyS*
用的 serial8250 的驱动,这个驱动比较原始,尝试过用e1000的驱动也可以使用,参考jslinux带网络功能的内核
tapper.c 在jslinux内建立tap0,tap_wsh.py 在vm里建立tap设备websockettunt0,基本原理相同.
jslinux:tap0
--->jslinux:8250驱动的/dev/ttyS1 -
--->websocket
---> vm:websockettunt0
在jslinux中: ping 10.0.2.1
在server中:tcpdump -i websockettunt0 查看流量
FAQ:
1.双jslinux网络不通的问题?
答:两个jslinux-tap浏览器要都在可见的地方,不能放在tab下面,一个没有写显示就不会加载,tap_wsh.py 中的select不是可读写状态
2. 服务端的代码在哪?
答:jslinux-tap/websocketstuntap的下面,使用的mod_pywebsocket
3.jslinux里面怎么和浏览器交互:
答:通过textarea,这部分需要内核驱动支持,
代码在https://github.com/killinux/jslinux-kernel/ 的src/patch_linux-2.6.20里,定义了jsclipboard这个设备,对应在jslinux里的/dev/clipboard
想把内容从jslinux传到浏览器的textarea就使用
echo "haha" >/dev/clipboard
如果想从浏览器传到jslinux里, 在textarea修改内容后 ,
cat /dev/clipboard
jslinux里面的网络设备就是通过这个建立的
cat /dev/clipboard |sh
4.如果我想重新编译内核这么办:
答:具体参考 https://www.iteye.com/blog/haoningabc-2338061
目前用2.6.20内核需要一些补丁,补丁的代码在代码在 https://github.com/killinux/jslinux-kernel
注意linuxstart.bin 和vmlinux-2.6.20.bin要一起重新编译,linuxstart里面定义了从第几字节开始加载内核
5.如果想重新制作硬盘怎么办:
答:
1.把散落的硬盘文件合并成一个,并挂在到本地系统
cd jslinux-tap/hao
cat hda000000*.bin > hda.bin
mount -t ext2 -o loop hda.bin /mnt/jshda
cp -r /mnt/jshda jslinux
2.在/mnt/jshda里面修改jslinux硬盘内的文件
3.再把修改过的硬盘拆分成小块给jslinux使用
split -a 9 -d -b 65536 hda.bin hda
for f in hda000000*; do
mv $f $f.bin
done
这里拆成较快是为了加快浏览器读取硬盘的速度, 具体读取代码在jslinux-tap/jslinux.js里面
params.hda = { url: "hao/hda%d.bin", block_size: 64, nb_blocks: 912 };
其他可能的想法和todo:
1、改成webrtc的版本,未实现
2、单桥多vm互通,已解决
3、net0其实没用,用serial2传的数据,需要单独编译网络驱动,验证通过。
4、硬盘问题:大文件加载后到indexdb ,计划减少第二次加载时间
5、线上修改之后如何保存到本地,回写问题,如何保存,如何同步?
6、开机状态迁移,内存怎么保存和移动?
7、hdb ,第二块硬盘怎么建立?
8、server端建立的tap设备,在websocket断掉后怎么自动清除
9、后续支持ssh协议
其他说明:
1.内核建立tap设备通过websocket与底层连接,传输层协议
2.底层python的服务端使用vxlan与openvswitch可以支持集群。
3.页面network status显示网络状态,红色网络异常,请刷新页面
4.chrome的开发者工具可以查看传输层协议
测试方式:
在命令行输入:
ifconfig
如果没有手网络设备,动建立tap设备
cat /dev/clipboard |sh
建立tap设备与websocket通信 测试网关
ifconfig
ping 10.0.2.1
测试dns
ping 8.8.8.8
ping www.baidu.com
理论上两个chrome浏览器可以用jslinux互相ping通