方永、南天紫云

道亦有道

OpenWrt自动fucking墙記錄
2015年02月06日

做中轉的路由器更新到OpenWrt BarrierBreaker 14.07 後,趁熱乎把自動fucking牆也部署上了。

一、 首先得有個牆外的VPS。

VPS的好處就是方便靈活,一年不到10USD的很多,找一個速度快靠譜點的就可以。

在VPS上面用shadowsocks-libev架一個ss服務,注意打開-u參數,做DNS中轉查詢會用到。

二、 然後是作爲網關幷已刷OpenWrt的路由器。

淘寶上一大堆。

注意OpenWrt的版本,用最新版的最好。

三、 大致思路如下:

在瀏覽器中使用PAC幷根據域名翻,瀏覽器會將包含域名的url請求發送給socks5代理幷接收返回的數據。與瀏覽正常的網站相比,瀏覽器沒有做DNS的解析請求, DNS的解析在socks5的服務端完成。

而瀏覽器訪問網站通常的流程,DNS解析與發送HTTP請求是分開的,DNS解析與HTTP都要在網關的參與下進行(隻考慮一般情況)。現在已經有了網關的最高權限,那麼隻需將那些被牆的網站根據域名做一個列表,若HTTP請求中的host在這個列表中,那麼將其轉至shadowsocks處理即可。當然,HTTP請求中的host會在HTTP請求發起前去做DNS解析的請求。在OpenWrt中,DNS服務端是dnsmasq,做請求中轉的是Linux內核防火牆(由iptables操作),shadowsocks是ss-redir

於是,被牆的域名列表交給dnsmasq,dnsmasq在返回查詢記錄的同時,會給存在于域名列表中的IP打個標記(由IPSET實現)。Linux的內核防火牆會將打這個標記的請求轉發給ss-redir。

dnsmasq作爲DNS服務端,只是做DNS解析的中轉與緩存,它會將DNS解析請求進一步發送給上級DNS服務端,這個上級DNS服務端,一般由通訊運營商提供,幷在pppoe或DHCP時獲得。問題是,這個上級DNS服務端返回的解析結果幷不可靠,尤其是那些被牆的域名。好在dnsmasq可以爲每個域名指定單獨的DNS服務端,於是將之前那個被牆域名列表複製一份,幷指定去一個可靠的DNS服務端獲取解析結果。

這個可靠的DNS服務端,一般由pdnsdChinaDnsdns over tunnel等實現,pdnsd使用TCP協議從國外可靠的DNS服務端獲取結果,ChinaDns丟棄假的幷接收真正的查詢結果,dns over tunnel就是將DNS的查詢通過一個可靠的隧道來保證查詢結果的正確,shadowsocks的ss-tunnel就可以做這個隧道。

四、 配置過程如下:

  1. 在OpenWrt中安裝shadowsocks。

    在shadowsocks官網下載至OpenWrt中用opkg安裝即可。

  2. 安裝dnsmasq。

    OpenWrt的固件中就集成了dnsmasq,但是幷沒有ipset的功能,需要安裝完全版。

        opkg update
        opkg remove dnsmasq
        opkg install dnsmasq-full
        opkg install kmod-ipt-ipset ipset
    
  3. 配置參考:

    (1) shadowsocks服務腳本:

        #!/bin/sh /etc/rc.common
    
        START=95
        
        USE_PROCD=1
        
        SS_LOCAL=/usr/bin/ss-local
        SS_REDIR=/usr/bin/ss-redir
        SS_TUNNEL=/usr/bin/ss-tunnel
        
        CONFIG=/etc/shadowsocks.json
        
        start_service()
        {
                procd_open_instance
                procd_set_param respawn
                procd_set_param command "$SS_LOCAL"
                procd_append_param command -c "$CONFIG"
                procd_close_instance
        
                procd_open_instance
                procd_set_param respawn
                procd_set_param command "$SS_REDIR"
                procd_append_param command -c "$CONFIG"
                procd_append_param command -b "0.0.0.0"
                procd_append_param command -l "8080"
                procd_close_instance
        
                procd_open_instance
                procd_set_param respawn
                procd_set_param command "$SS_TUNNEL"
                procd_append_param command -c "$CONFIG"
                procd_append_param command -b "127.0.0.1"
                procd_append_param command -l "5353"
                procd_append_param command -L "8.8.8.8:53"
                procd_append_param command -u
                procd_close_instance
        }
    

    (2) dnsmasq配置:

    /etc/dnsmasq.conf中添加一句conf-dir=/etc/dnsmasq.conf.d

    /etc/dnsmasq.conf.d/agw_list中內容如下:

        server=/www.google.com/127.0.0.1#5353
        ipset=/www.google.com/agw
    

    每一個域名有兩條這樣的記錄。

    (3) 防火牆配置:

    /etc/firewall.user中增加如下內容:

        ipset -N agw iphash
        iptables -t nat -A PREROUTING -p tcp -m set --match-set agw dst -j REDIRECT --to-port 8080