前言

shadowsocks是个非常棒的翻墙代理,它可以在本地提供一个socks5端口供软件使用代理。比如启动chrome的时候加上--proxy-server="socks5://myproxy:1080"这条参数就可以让chrome走代理;然而,有些软件不支持设置代理的功能。所以有时候,我们需要一个全局代理的环境,使用VPN是一个通常的选择,不过一般购买的VPN的速度不如shadowsocks,同时,VPN更容易受到GFW的干扰。为什么不把正在使用的shadowsocks利用起来作为一个全局代理呢?

本文介绍了一种利用redsocks与iptables实现全局代理的方法,其基本原理如下:

  1. iptables的规则将所有tcp包转发到redsocks打开的本地端口
  2. redsocks接收tcp包并转发给shadowsocks打开的本地socks端口
  3. shadowsocks将接收的包转发给远端的代理服务器

由于使用了redsocks与iptables,因此本文的方法仅适用于Linux。

安装

由于使用的是Arch Linux,我直接通过AUR安装

$ yaourt redsocks

通过yaourt搜索redsocks包,然后选择你要安装的包的序号就可以进行安装了。

注意:下文中的配置文件的路径全部基于Arch Linux,如果你用的不是Arch Linux,请根据自己的情况更改。

其他发行版可以通过各自的包管理器或者下载源码安装

配置

配置redsocks

我在包提供的原有配置的基础上进行了一些修改,主要是把 redsocks -> port 修改为shadowsocks的本地端口(1080),另外,由于只需要转发tcp流量,我把 redudpdnstc 段的配置全部注释了。注意 redsocks -> local_port 配置的端口是用来接收iptables传来的流量用的,设置为一个不会和别的程序冲突的端口,但要保证和iptables规则里的端口对应。

$ vim /etc/redsocks.conf
base {
    // debug: connection progress & client list on SIGUSR1
    log_debug = off;

    // info: start and end of client session
    log_info = off;

    /* possible `log' values are:
     *   stderr
     *   "file:/path/to/file"
     *   syslog:FACILITY  facility is any of "daemon", "local0"..."local7"
     */
    // log = stderr;
    // log = "file:/path/to/file";
    log = "syslog:daemon";

    // detach from console
    daemon = on;

    /* Change uid, gid and root directory, these options require root
     * privilegies on startup.
     * Note, your chroot may requre /etc/localtime if you write log to syslog.
     * Log is opened before chroot & uid changing.
     */
    user = redsocks;
    group = redsocks;
    // chroot = "/var/chroot";

    /* possible `redirector' values are:
     *   iptables   - for Linux
     *   ipf        - for FreeBSD
     *   pf         - for OpenBSD
     *   generic    - some generic redirector that MAY work
     */
    redirector = iptables;
}

redsocks {
    /* `local_ip' defaults to 127.0.0.1 for security reasons,
     * use 0.0.0.0 if you want to listen on every interface.
     * `local_*' are used as port to redirect to.
     */
    local_ip = 127.0.0.1;
    local_port = 31338;

    // listen() queue length. Default value is SOMAXCONN and it should be
    // good enough for most of us.
    // listenq = 128; // SOMAXCONN equals 128 on my Linux box.

    // `max_accept_backoff` is a delay to retry `accept()` after accept
    // failure (e.g. due to lack of file descriptors). It's measured in
    // milliseconds and maximal value is 65535. `min_accept_backoff` is
    // used as initial backoff value and as a damper for `accept() after
    // close()` logic.
    // min_accept_backoff = 100;
    // max_accept_backoff = 60000;

    // `ip' and `port' are IP and tcp-port of proxy-server
    // You can also use hostname instead of IP, only one (random)
    // address of multihomed host will be used.
    ip = 127.0.0.1;
    // 修改为shadosocks的本地端口
    port = 1080;


    // known types: socks4, socks5, http-connect, http-relay
    type = socks5;

    // login = "foobar";
    // password = "baz";
}

//redudp {
    // `local_ip' should not be 0.0.0.0 as it's also used for outgoing
    // packets that are sent as replies - and it should be fixed
    // if we want NAT to work properly.
    //local_ip = 127.0.0.1;
    //local_port = 10053;

    // `ip' and `port' of socks5 proxy server.
    //ip = 127.0.0.1;
    //port = 1080;

    // login = username;
    // password = pazzw0rd;

    // kernel does not give us this information, so we have to duplicate it
    // in both iptables rules and configuration file.  By the way, you can
    // set `local_ip' to 127.45.67.89 if you need more than 65535 ports to
    // forward ;-)
    // This limitation may be relaxed in future versions using contrack-tools.
    //dest_ip = 8.8.8.8;
    //dest_port = 53;

    //udp_timeout = 30;
    //udp_timeout_stream = 180;
//}

//dnstc {
    // fake and really dumb DNS server that returns "truncated answer" to
    // every query via UDP, RFC-compliant resolver should repeat same query
    // via TCP in this case.
//  local_ip = 127.0.0.1;
//  local_port = 5300;
//}

// you can add more `redsocks' and `redudp' sections if you need.

iptables规则

也是在包提供的原有配置的基础上进行了一些修改,唯一的修改只是增加了这一条

-A REDSOCKS -d proxy_server_ip -j RETURN,使代理自己不要再被重定向,不然就无限循环了。。

$ vim /etc/iptables/redsocks.rules
# Transparent SOCKS proxy
# See: http://darkk.net.ru/redsocks/

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:REDSOCKS - [0:0]

# Redirect all output through redsocks
-A OUTPUT -p tcp -j REDSOCKS

# Whitelist LANs and some other reserved addresses.
# https://en.wikipedia.org/wiki/Reserved_IP_addresses#Reserved_IPv4_addresses
-A REDSOCKS -d 0.0.0.0/8 -j RETURN
-A REDSOCKS -d 10.0.0.0/8 -j RETURN
-A REDSOCKS -d 127.0.0.0/8 -j RETURN
-A REDSOCKS -d 169.254.0.0/16 -j RETURN
-A REDSOCKS -d 172.16.0.0/12 -j RETURN
-A REDSOCKS -d 192.168.0.0/16 -j RETURN
-A REDSOCKS -d 224.0.0.0/4 -j RETURN
-A REDSOCKS -d 240.0.0.0/4 -j RETURN
# import shadowsocks server ip
#-A REDSOCKS -d xxx.xxx.xxx.xxx -j RETURN
# shadowsocks server port
-A REDSOCKS -p tcp --dport xxxxx -j RETURN

# Redirect everything else to redsocks port
-A REDSOCKS -p tcp -j REDIRECT --to-ports 31338

COMMIT

运行

开启redsocks和iptables服务,并让它们开机自启:

$ sudo systemctl start  redsocks.service iptables.service
$ sudo systemctl enable  redsocks.service iptables.service

当你需要进入全局代理时,简单地导入redsocks.rules就行:

$ sudo iptables-restore < /etc/iptables/redsocks.rules

当你需要退出全局代理环境,只需要清空iptables规则,redsocks可以让他一直运行:

$ sudo /usr/lib/systemd/scripts/iptables-flush

一些人可能是自己编译源码进行安装的,这些Arch Linux软件包内的默认配置和运行脚本可能对你有所帮助。

高级配置

由于我只在极少数特殊情况下才会用到全局代理,所以DNS防污染,国内ip白名单等都没有弄,有需要的可以研究下以下几个技术:

  1. dnsmasq

  2. pdnsd

  3. chnroutes

  4. ChinaDNS

  5. Pcap_DNSProxy