Pages

Tuesday, 27 October 2015

OpenWrt 上使用 Python 操作 TAP/TUN

这两天折腾 tun,之前完全没接触驱动这么底层的东西,全靠 GlacJAY 大大的这篇文章入门了。
一句话,参照此 gist,同时将TUNSETIFF = 0x400454ca改为TUNSETIFF = -2147199798 即可。
那篇文章的代码在 Windows 和 Ubuntu 下都正常运行,但今天在路由器上运行时却报错了:
Traceback (most recent call last):
  ……
  File "/root/movpn/tun.py", line 218, in _open_tun
    fcntl.ioctl(tun, TUNSETIFF, ifr)
IOError: [Errno 81] File descriptor in bad state
因为 vtun 运行正常,所以 tun 本身应该是没问题的。又测试了一下,这个错误在 ioctl 的request不正确时出现。遂铺天盖地地寻找此值,发现不少相同遭遇,如这里还有这,但没找到解决方案。
先去解了 ioctl,得知第二个参数是由好几个部分组成的,从 if_tun.h 找到了 ioctl.h,最后卡在一点C语言也不会,琢磨半天也没弄明白 TUNSETIFF 取值多少..
无奈,只好试着自己写段代码把 TUNSETIFF 打出来了..
之前只听说过 交叉编译 这个词,现在就要动手了好鸡冻,好在 OpenWrt 的相关资料很丰富:参照 wiki 以及 这篇帖子 外加一晚上时间终于完成了。
找了一个 C Hello Word 改了一下:
#include 
#include <linux/if_tun.h>
#include <sys/ioctl.h>
 
main() {
    printf("TUNSETNOCSUM  = %d\n", TUNSETNOCSUM);
    printf("TUNSETDEBUG   = %d\n", TUNSETDEBUG);
    printf("TUNSETIFF     = %d\n", TUNSETIFF);
    printf("TUNSETPERSIST = %d\n", TUNSETPERSIST);
    printf("TUNSETOWNER   = %d\n", TUNSETOWNER);
    printf("TUNSETLINK    = %d\n", TUNSETLINK);
    printf("TUNSETGROUP   = %d\n", TUNSETGROUP);
}
交叉编译:
xx@xx:~/openwrt/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2$ \
    bin/mips-openwrt-linux-gcc test.c
上传路由器,执行:
TUNSETNOCSUM  = -2147199800
TUNSETDEBUG   = -2147199799
TUNSETIFF     = -2147199798
TUNSETPERSIST = -2147199797
TUNSETOWNER   = -2147199796
TUNSETLINK    = -2147199795
TUNSETGROUP   = -2147199794
OK,全出来了,话说为啥都是负数 = = 和 CPU 位宽整数长度啥的有关?换一个路由器是否还是这个值?
不知道,管用就行,Python 里TUNSETIFF = -2147199798就好了。
P.s. 嘛其实回想起来也不复杂,就是编译 OpenWrt 略显蛋疼:经常在各种下载时卡住,挂VPN、断VPN,反复试。 有个 git clone 就是卡在 84% 死活过不去,最后把 git:// 改成 https:// 才好。
from https://blog.sorz.org/p/openwrt-py-tun/