:::tips 由于笔记本经常重启, 于是把开发环境放到了远程, 在 docker container 进行开发, 但是远程的 Linux 系统不能”上网”, 于是有了本文档 :::

原理和方法

  • 将本机所有的流量 通过 iptables 重定向到 redsocks, 再由 redsocks 转发到代理端口
  • 本文使用中关键的技术点在使用 iptables owner 模块过滤掉 redsocks 和代理程序本身流量, 来解决代理流量死循环的问题
  • redsocks 可以转发 udp 流量, 这意味着你配置得当, 就能避免 DNS 污染

Docker API 访问, 设置 tls 认证 - 进行 vscode 远程容器开发

运行容器

  • 运行一个容器, 用于运行 redsocks 和 clash
  • 这是我用于 vscode 开发的远程容器镜像, 本身不包含任何应用服务
  • 编辑这和镜像启动后运行的文件 /root/workspace/.vscode.init/start.sh (root目录是映射到外部的, 可以从外面编辑) ```bash __run_container() { _name=”service-clash” docker rm -f “$_name” docker run -itd \
    1. --name="$_name" \
    2. --network="host" \
    3. --restart=unless-stopped \
    4. --privileged \
    5. -v /proc:/host \
    6. -v /data/docker-data/$_name:/root \
    7. registry.cn-hangzhou.aliyuncs.com/lwmacct/vscode:docker-env-v1.0.4-20221104
    }

__run_container

  1. <a name="bpbDX"></a>
  2. # 启动脚本
  3. - 注意下面的内容是在容器 service-clash 内部的操作
  4. - 编辑容器内的启动
  5. ```bash
  6. /root/workspace/.vscode.init/start.sh

__iptables() { _table=”M_OUTPUT_REDSOCKS_CLASH” iptables -t nat -F $_table iptables -t nat -X $_table iptables -t nat -N $_table

  1. iptables -t nat -A "$_table" -m owner --gid-owner 5001 -j RETURN
  2. iptables -t nat -A "$_table" -d 127.0.0.0/8 -j RETURN
  3. iptables -t nat -A "$_table" -p tcp -j REDIRECT --to-ports 12345
  4. iptables -t nat -A "$_table" -p udp -j REDIRECT --to-ports 10053
  5. iptables -t nat -A "$_table" -p icmp -j REDIRECT --to-ports 10053
  6. # 加入主链
  7. if [[ "$(iptables -t nat -L OUTPUT | grep "^$_table\s" -c)" == "0" ]]; then
  8. iptables -t nat -I OUTPUT 1 -j $_table
  9. # iptables -t nat -D OUTPUT -j M_OUTPUT_REDSOCKS_CLASH # 解除代理状态
  10. fi
  11. # iptables -t nat -nvL

}

__main() { cd /root/workspace/app/ || return 0

  1. if [[ "$(which redsocks | wc -l)" == "0" ]]; then
  2. apt update && apt install -y redsocks iptables
  3. if [ ! -f "redsocks.conf" ]; then
  4. cat /etc/redsocks.conf >./redsocks.conf
  5. fi
  6. sed 's@^redsocks:.*@redsocks:x:0:5001::/var/run/redsocks:/bin/bash@' -i /etc/passwd
  7. fi
  8. if [[ "$(which redsocks | wc -l)" == "1" ]]; then
  9. sudo -u redsocks bash -c "nohup ./clash-linux-amd64 -d data/ >log/clash.log &"
  10. redsocks -c redsocks.conf
  11. __iptables
  12. iptables -t nat -nvL
  13. fi

}

__main

  1. <a name="pUC7X"></a>
  2. # redsocks 配置模板, 仅供参考
  3. redsocks.conf 文件

base { // debug: connection progress & client list on SIGUSR1 log_debug = off;

  1. // info: start and end of client session
  2. log_info = on;
  3. /* possible `log' values are:
  4. * stderr
  5. * "file:/path/to/file"
  6. * syslog:FACILITY facility is any of "daemon", "local0"..."local7"
  7. */
  8. log = "syslog:daemon";
  9. // detach from console
  10. daemon = on;
  11. /* Change uid, gid and root directory, these options require root
  12. * privilegies on startup.
  13. * Note, your chroot may requre /etc/localtime if you write log to syslog.
  14. * Log is opened before chroot & uid changing.
  15. */
  16. user = redsocks;
  17. group = redsocks;
  18. // chroot = "/var/chroot";
  19. /* possible `redirector' values are:
  20. * iptables - for Linux
  21. * ipf - for FreeBSD
  22. * pf - for OpenBSD
  23. * generic - some generic redirector that MAY work
  24. */
  25. redirector = iptables;

}

redsocks { /* `local_ip’ defaults to 127.0.0.1 for security reasons,

  1. * use 0.0.0.0 if you want to listen on every interface.
  2. * `local_*' are used as port to redirect to.
  3. */
  4. local_ip = 127.0.0.1;
  5. local_port = 12345;
  6. // `ip' and `port' are IP and tcp-port of proxy-server
  7. // You can also use hostname instead of IP, only one (random)
  8. // address of multihomed host will be used.
  9. ip = 127.0.0.1;
  10. port = 7890;
  11. // known types: socks4, socks5, http-connect, http-relay
  12. type = socks5;
  13. // login = "foobar";
  14. // 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;

  1. // `ip' and `port' of socks5 proxy server.
  2. ip = 127.0.0.1;
  3. port = 7890;
  4. // login = username;
  5. // password = pazzw0rd;
  6. // kernel does not give us this information, so we have to duplicate it
  7. // in both iptables rules and configuration file. By the way, you can
  8. // set `local_ip' to 127.45.67.89 if you need more than 65535 ports to
  9. // forward ;-)
  10. // This limitation may be relaxed in future versions using contrack-tools.
  11. dest_ip = 127.0.0.53;
  12. dest_port = 53;
  13. udp_timeout = 30;
  14. 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' andredudp’ sections if you need.

  1. 差异对比

root@localhost:/# diff /etc/redsocks.conf /root/workspace/app/redsocks.conf 48c48

< port = 1080;

  1. port = 7890;

66,69c66,69 < ip = 192.0.2.1; < port = 1080; < login = username;

< password = pazzw0rd;

  1. ip = 127.0.0.1;
  2. port = 7890;
  3. // login = username;
  4. // password = pazzw0rd;

76c76

< dest_ip = 192.0.2.2;

  1. dest_ip = 127.0.0.53;

root@localhost:/# ```

推荐阅读

clash可以用作全局代理程序吗? · Issue #292 · Dreamacro/clash
Clash作为透明代理是否有意义? · Issue #158 · Dreamacro/clash
GitHub - darkk/redsocks: transparent TCP-to-proxy redirector
GitHub - blue7wings/clash-tun: 在Linux环境中设置clash tun模式,以便达到全局代理的功能