OpenWRT – 折腾(存档) https://blog.sorz.org 已停止更新和维护。该页面为2018年3月创建的存档,其内容可能已过于陈旧、与现状不符,仅作为历史存档用作参考。 Sun, 14 Jan 2018 11:08:20 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.9.4 OpenWrt VPN 按域名路由 /p/openwrt-outwall/ /p/openwrt-outwall/#comments Thu, 22 May 2014 14:50:23 +0000 https://sorz.org/?p=347911 简述

这是一种基于域名的 VPN 智能翻越方案。不同于 chnroutes 这类通过维护一个 IP 地址列表来区分国内外网站的方案,基于域名的方式不受 IP 地址变动的影响。仅需维护一个相对很少有变化的域名列表即可。

dnsmasq 在 2.66 版之后加入了对 ipset 的支持,可将指定域名的 IP 解析后自动加入某一 ipset 中。 再配置路由规制,使该 ipset 中的 IP 走 VPN 即可。

感谢 @wzyboy 提供了此方案的思路。

大致流程

  • 配置 VPN
  • 配置 dnsmasq,指定域名
  • 增加一个路由表,默认网关为 VPN
  • 使用 iptables 匹配 ipset 并打上 mark
  • 使用 ip rule 将打上 mark 的包送入该路由表

所需软件

  • iproute2
  • dnsmasq (>= 2.66, has ipset)
  • iptables (with ipset and mark modules)

opkg update
opkg install ip ipset kmod-ipt-ipset dnsmasq-full

OpenWrt 默认的dnsmasq包并不包含 ipset 支持,需安装dnsmasq-full(感谢 @leavic 的提醒)。亦可修改 makefile 自行编译,以节省空间。

配置文件

列举一下涉及的各部分配置文件,供参考。

VPN

各类 VPN 均可,请参考 VPN overview。注意请将 VPN 设为默认路由。

rt_tables

添加outwall路由表。 走 VPN 的流量都将使用此表。

echo "200 outwall" >> /etc/iproute2/rt_tables

rc.local

使系统启动时创建一个名为outwall的 ipset。
在 /etc/rc.local 中添加:

# vi /etc/rc.local
ipset create outwall hash:ip

名字可以随便取,与 dnsmasq.conf 和 firewall.user 中的保持一致即可。

firewall.user

将匹配 ipset outwall的包全部标上 mark 8。
在 /etc/firewall.user 中添加:

# vi /etc/firewall.user
iptables -t mangle -A fwmark -m set --match-set outwall dst -j MARK --set-mark 8

打上 mark 以后,就可以指定它们所使用的路由表了。
mark 值可随便选,保持一致即可。若同时装有 qos-scripts,mark 可选一个较大的值,以防与其发生冲突。

VPN Post-connected Script

确保以下脚本在每次 VPN 连接建立后执行。
不同 VPN 的配置方法可能不同。 一个比较通用的方法是使用 Hotplug

(我这次用的是 vpnc,所以比较偷懒地将脚本放在了/etc/vpnc/post-connect.d/下)

#!/bin/sh
ip route add 8.8.8.8 dev $TUNDEV
ip route add default dev $TUNDEV table outwall
ip rule add fwmark 8 table outwall

注意,须将$TUNDEV替换为 VPN 设备名,比如ppp0

这段脚本有三个作用:

  1. 让 8.8.8.8 走 VPN,防止 DNS 污染;
  2. 由于 VPN 断线时相关路由会被自动删除,所以在需要每次连接时添加一次;
  3. ip rule 在 VPN 断线时将手动删除(见下一节),切换至正常路由。

VPN Disconnect Script

见上节说明,须在 VPN 断线时 自动执行的脚本:

#!/bin/sh
ip rule del table outwall

dnsmasq.conf

请参考 dnsmasq man(8)
修改 /etc/dnsmasq.conf,在其中加入需要翻越的域名。 格式如下:

server=/域名/8.8.8.8
ipset=/域名/outwall
  • server将指定域名使用 8.8.8.8 查询(8.8.8.8 已配置为走 VPN,防止 DNS 污染);
  • ipset将指定域名的所有 IP 加入 ipset outwall中;
  • 可在一行添加多个域名,如ipset=/twitter.com/t.co/outwall
  • google.com将同时匹配 google.com 和 plus.google.com。com将匹配所有 .com 结尾域名。

一个可供参考的配置如下, 该配置:

  • 尽可能地让 Google 所有常用服务走 VPN
  • 允许访问 Facebook、Twitter 和 YouTube
  • 让 GitHub 的 CDN 走 VPN
server=/google.com/8.8.8.8
server=/googleusercontent.com/8.8.8.8
server=/gstatic.com/8.8.8.8
server=/googlehosted.com/8.8.8.8
server=/golang.org/8.8.8.8
server=/googleapis.com/8.8.8.8
ipset=/google.com/outwall
ipset=/googleusercontent.com/outwall
ipset=/gstatic.com/outwall
ipset=/googlehosted.com/outwall
ipset=/golang.org/outwall
ipset=/googleapis.com/outwall

server=/twitter.com/8.8.8.8
server=/twimg.com/8.8.8.8
server=/t.co/8.8.8.8
ipset=/twitter.com/outwall
ipset=/twimg.com/outwall
ipset=/t.co/outwall

server=/facebook.com/8.8.8.8
ipset=/facebook.com/outwall

server=/youtube.com/8.8.8.8
server=/ytimg.com/8.8.8.8
server=/ggpht.com/8.8.8.8
server=/youtu.be/8.8.8.8
server=/googlevideo.com/8.8.8.8
server=/youtube-nocookie.com/8.8.8.8
ipset=/youtube.com/outwall
ipset=/ytimg.com/outwall
ipset=/ggpht.com/outwall
ipset=/youtu.be/outwall
ipset=/googlevideo.com/outwall
ipset=/youtube-nocookie.com/outwall

server=/githubusercontent.com/8.8.8.8
server=/github.global.ssl.fastly.net/8.8.8.8
server=/githubapp.com/8.8.8.8
ipset=/githubusercontent.com/outwall
ipset=/github.global.ssl.fastly.net/outwall
ipset=/githubapp.com/outwall

关于 Shadowsocks

(更新于 2014-11-23)

补充说明一下,此方案亦可与 shadowsocks-libev 配合使用,配置起来会比 VPN 简单很多。自己用了几个月,体验良好。这里简单介绍一下配置方法。

1、在 shdowsocks.org 可以下载到已编译的 ipk 包,在 OpenWrt 上安装即可。

2、配置好 Shadowsocks,并运行,注意服务器那边需要支持 UDP 转发(请使用较新版并配好防火墙)。OpenWrt 中使用ss-redir代理 TCP 连接,使用ss-tunnel代理 DNS 查询。具体参数请参考范例:

ss-redir -c /etc/shadowsocks.json -l 1080
ss-tunnel -c /etc/shadowsocks.json -l 5533 -L 8.8.8.8:53 -u

3、在/etc/firewall.user中加入(参考):

iptables -t nat -N shadowsocks
iptables -t nat -A shadowsocks -m set ! --match-set outwall dst -j RETURN
iptables -t nat -A shadowsocks -p tcp --syn -m connlimit --connlimit-above 32 -j RETURN
iptables -t nat -A shadowsocks -p tcp -j REDIRECT --to-ports 1080

iptables -t nat -A PREROUTING -s 192.168.0.0/16 -j shadowsocks

这将使匹配outwall(这个 IPSet)的 TCP 连接指向ss-redir。后者将为这些连接建立隧道并通过 Shadowsocks 协议加密发送。

4、/etc/dnsmasq.conf中不再使用8.8.8.8,而是使用127.0.0.1#5533,范例如下:

server=/google.com/127.0.0.1#5533
ipset=/google.com/outwall

这将使 dnsmasq 将 DNS 查询请求发送至ss-tunnel,后者在将其通过 SS 转送至 Google Public DNS。

由于不再涉及路由,不需要安装配置iproute2,不再需要使用-j MARK打标记。当然,也不用在配置 VPN 及相关脚本。

优点:方便配置,不管是路由器还是服务器。
缺点:只代理 TCP 连接,UDP、ICMP (ping) 等无法使用。

]]>
/p/openwrt-outwall/feed/ 22
OpenWrt 上使用 Python 操作 TAP/TUN /p/openwrt-py-tun/ /p/openwrt-py-tun/#comments Sat, 27 Apr 2013 18:58:40 +0000 http://sorz.org/?p=347635 这两天折腾 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:// 才好..

]]>
/p/openwrt-py-tun/feed/ 6
WR703n OpenWrt 作无线交换机 /p/opwrt-switch/ /p/opwrt-switch/#respond Sat, 01 Dec 2012 15:06:08 +0000 http://ouno.tk/?p=347504 不知道标题描述是否准确… 就是普通无线路由器,只插入一根网线到 LAN 口的效果..
因为 TL-WR703n 只有一个RJ45口,所以可能需要改些配置.. 两个月前做过一次,现在我几乎忘了要怎么配置了,赶紧记下来..

修改 /etc/config/network ,注释掉原 wan 和 lan 设置。然后添加:

config interface lan
    option type   'bridge'
    option ifname 'eth0'
    option proto  'dhcp'

嗯..这样就行了.. 执行 /etc/init.d/network restart 生效。
第一行 lan 和 /etc/config/wireless 里的 network 对应就好。
最后一行 proto 只是方便连接路由器后台而已,按实际环境改,随便设也不影响使用就是了。

顺带一提,搞坏了连不上路由器时,可以进安全模式..
连上网线,设置IP 192.168.1.2。路由开机,等待几秒钟,待 LED 开始闪烁时,轻捅菊花。如果时机正确,LED 将狂闪不止..
此时 telnet 192.168.1.1 连接,然后 mount_root 一下,就可以修改设置了。

(如果开机马上捅菊,可能可进 failure safe 刷机)

]]>
/p/opwrt-switch/feed/ 0
WR703n OpenWrt 按网络流量闪烁LED /p/flashled/ /p/flashled/#comments Sun, 22 Jul 2012 17:07:28 +0000 http://xierch.tk/?p=347365 #UPDAT130215: 感谢 @dword1511 提醒,闪灯是自带功能直接设置即可:

echo phy0tx > /sys/class/leds/tp-link\:blue\:system/trigger

另外,除了 phy0tx,trigger 还有几个可选值:
[none] default-on timer phy0rx phy0tx phy0assoc phy0radio phy0tpt netdev usbdev

当然本文脚本还是有一定价值的:比如可以一眼区分出 100KiB/s 与 1MiB/s
———-

前几天TB上搞了一个火柴盒形的路由器,TP-Link WR703n
单RJ45口,USB2.0,改外置天线改 64M 内存,改 8M Flash,刷了 OpenWrt 便于折腾。

盒子上只有一颗蓝色 LED,开机后常亮,写了个脚本让它随网络流量闪烁:
以 1Hz 频率闪烁,根据流量调节占空比。无流量时常灭,满带宽时常亮。

下载脚本前,需要安装几个东西:

opkg update
opkg install lmbench-msleep bc

lmbench-msleep用来做毫秒级延时,bc用来计算小数。不是很大,各种依赖加起来几百K吧好像..)

脚本如下,修改好设置保存任意地方,加入rc.local开机自启动就好~

#!/bin/sh
#set -x
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"

IFNAME="eth0"
FULLSPEED=1200  # KiB/s
LED='/sys/class/leds/tp-link:blue:system/brightness'

while [ True ]
do

# Get traffic data:
str=$(ifconfig $IFNAME | grep 'RX bytes')
str=${str#*'RX bytes:'}
str=${str%' ('*}
str=${str%' ('*}
now=$((str/1024))

speed=$((now-last))
if [ "$speed" -gt "$FULLSPEED" ] ; then
        speed="$FULLSPEED"
fi
last="$now"

# Flash LED:
ratio=`echo "scale=3;$speed/$FULLSPEED*1000"|bc`
ontime=${ratio%'.'*}
offtime=$((1000-ontime))
#echo "$ontime"

if [ "$ontime" -gt "0" ] ; then
        echo 255 > "$LED"
        msleep "$ontime"
fi

if [ "$offtime" -gt "0" ] ; then
        echo 0 > "$LED"
        msleep "$offtime"
fi

#sleep 10
done

开头有两处可能要修改的地方:
IFNAME 为接口(interface)名称,ifconfig 里显示的那个,eth0、wlan0、pppoe-xxx 什么的都可以
FULLSPEED 为网络带宽,单位KiB/s,想调低常亮阈值就改小些…
如果不是 WR730n,可能还需要修改 LED

第一次写(超过10行的)bash 脚本,感觉好奇葩啊..各种蛋疼..
估计有的地方有绕圈子了?至少能运行了..要不是8M小路由器舍不得装 Python 我才不用 bash 嘞…

似乎还是狂闪的那种比较好看?但是好麻烦的样子…

]]>
/p/flashled/feed/ 2