2
7
2014
27

Linux「真」全局 HTTP 代理方案

本文来自依云's Blog,转载请注明。

看到 ArchWiki 上 GoAgent 条目的亚全局代理方案,只是设置了代理相关环境变量。我就想,为什么不实现一个真正的全局 HTTP 代理呢?

最终,答案是:Linux 太灵活了,以至于想写一个脚本来搞定很麻烦。不过方案如下,有兴趣的可以折腾折腾。

首先,需要用到的工具:dnsmasq、iptables、redsocks,以及 HTTP 代理工具。dnsmasq 是用来缓存 DNS 请求的,iptables 把 TCP 流转接到 redsocks,而 redsocks 将 TCP 流转接到代理上。

最小 dnsmasq 配置如下:

listen-address=127.0.0.1
cache-size=500
server=127.0.0.1#5353
bogus-nxdomain=127.0.0.1

这里使用了本地的 dnscrypt 服务(假设其在 5353 端口上提供服务)。也可以使用国外服务器,只是需要更细致的配置来迫使其走 TCP。

iptables 命令如下:

# 创建一个叫 REDSOCKS 的链,查看和删除的时候方便
iptables -t nat -N REDSOCKS
# 所有输出的数据都使用此链
iptables -t nat -A OUTPUT -j REDSOCKS

# 代理自己不要再被重定向,按自己的需求调整/添加。一定不要弄错,否则会造成死循环的
iptables -t nat -I REDSOCKS -m owner --uid-owner redsocks -j RETURN
iptables -t nat -I REDSOCKS -m owner --uid-owner goagent -j RETURN
iptables -t nat -I REDSOCKS -m owner --uid-owner dnscrypt -j RETURN

# 局域网不要代理
iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN

# HTTP 和 HTTPS 转到 redsocks
iptables -t nat -A REDSOCKS -p tcp --dport 80 -j REDIRECT --to-ports $HTTP_PORT
iptables -t nat -A REDSOCKS -p tcp --dport 443 -j REDIRECT --to-ports $HTTPS_PORT
# 如果使用国外代理的话,走 UDP 的 DNS 请求转到 redsocks,redsocks 会让其使用 TCP 重试
iptables -t nat -A REDSOCKS -p udp --dport 53 -j REDIRECT --to-ports $DNS_PORT
# 如果走 TCP 的 DNS 请求也需要代理的话,使用下边这句。一般不需要
iptables -t nat -A REDSOCKS -p tcp --dport 53 -j REDIRECT --to-ports $HTTPS_PORT

redsocks 的配置:

base {
  log_debug = off;
  log_info = off;
  daemon = on; 
  redirector = iptables;
}
// 处理 HTTP 请求
redsocks {
  local_ip = 127.0.0.1;
  local_port = $HTTP_PORT;
  ip = $HTTP_PROXY_IP;
  port = $HTTP_PROXY_PORT;
  type = http-relay; 
}
// 处理 HTTPS 请求,需要一个支持 HTTP CONNECT 的代理服务器,或者 socks 代理服务器
redsocks {
  local_ip = 127.0.0.1;
  local_port = $HTTPS_PORT;
  ip = $SSL_PROXY_IP;
  port = $SSL_PROXY_PORT;
  type = http-connect;  // or socks4, socks5
}
// 回应 UDP DNS 请求,告诉其需要使用 TCP 协议重试
dnstc {
  local_ip = 127.0.0.1;
  local_port = $DNS_PORT;
}

然后以相应的用户和配置文件启动 dnsmasq 以及 redsocks。修改/etc/resolv.conf

nameserver 127.0.0.1

至于分流的事情,HTTP 部分可以交给 privoxy,但是 HTTPS 部分不好办。可以再设立一个像 GoAgent 那样的中间人型 HTTPS 代理,或者更简单地,直接根据 IP 地址,国内的直接RETURN掉。

以上就是整个方案了。有些麻烦而我又不需要所以没测试。反正就是这个意思。Android 软件 GAEProxy 就是这么干的(不过它没使用 iptables 的 owner 模块,导致我不小心弄出了死循环)。另外,BSD 系统也可以使用类似的方案。

Category: Linux | Tags: linux 网络 代理 iptables redsocks | Read Count: 64886
adam8157 说:
Feb 07, 2014 07:59:07 PM

看标题还以为是用proxychains启动的login shell, LOL

MatheMatrix 说:
Feb 07, 2014 09:21:44 PM

为什么我觉得你需要的是一个装了 OpenWrt 的路由……

Avatar_small
λ 说:
Feb 08, 2014 11:32:14 AM

看来小白想要理解上面的东东还是有点困难……iptables 的局域网规则收藏了。
发现用 GAE 还是会被一些 Google 的网站屏蔽,写了白名单黑名单,依然有无法解决的问题,受不了最终还是用 socks 代理(VPS)配合 privoxy 一劳永逸。

Star Brilliant 说:
Feb 08, 2014 01:01:00 PM

REDSOCKS我以前配置过,一直没有成功。回去再试试看。

Avatar_small
依云 说:
Feb 10, 2014 04:49:48 PM

那个在 sudo 时也会被重置掉的啦。

Avatar_small
依云 说:
Feb 10, 2014 04:50:51 PM

因为你有一个装了 OpenWrt 的路由器 :-)

Star Brilliant 说:
Feb 10, 2014 05:06:12 PM

HTTPS 请求试试看 sniproxy 哟。

Avatar_small
依云 说:
Feb 10, 2014 05:41:41 PM

这个似乎不错呢喵呜~

MaskRay 说:
Apr 06, 2014 10:05:18 PM

我現在在用修改路由表的方案,把apnic上國內ip都走正常網關,default是vpn。還要一個遞歸解析並緩存的dns client……很需要一個 proxychains 這樣的工具,但能更方便的設置代理

Avatar_small
依云 说:
Apr 06, 2014 10:37:12 PM

你自己改改 proxychains?

网友 说:
May 21, 2014 05:28:28 PM

博主好,不错的 方案,可以实现。但是 操作起来 遇到个 问题。goagent 和 redsocks 的 --uid-owner 找不到,还有什么方法 解决 gae的流量 被代理吗?

Avatar_small
依云 说:
May 21, 2014 06:05:00 PM

「--uid-owner 找不到」?是你的 iptables 不支持按 UID 匹配,还是你的 goagent 和 redsocks 没有用单独的用户?

lxfan 说:
Jun 02, 2014 09:20:35 PM

之前一直不会设置iptables,老是设置好了就无法打开网页,估计是死循环了,iptables -t nat -I REDSOCKS -m owner --uid-owner root -j RETURN加了root之后就好了,自己也编译了redsocks2安卓版,却无法再安卓上正常使用,提示找不到libevent-2.0.so.5,将编译好的安卓libevent动态库放在/system/lib下,并做软连接为libevent-2.0.so.5,就又提示event_loopbreak错误,希望能指导一下,谢谢,不知道哪里出了问题

Avatar_small
依云 说:
Jun 03, 2014 11:14:17 AM

你使用的 Android NDK 编译的吗?完整的错误消息是什么?redsocks2 是 redsocks 的 fork 吗,我没找到它的官网呢。

lxfan 说:
Jun 03, 2014 10:10:06 PM

是用的Android NDK编译的,方法和编译redsocks一样,redsocks我自己编译好能用,redsocks2的网址:https://github.com/semigodking/redsocks,应该是一个作者的,你看看呢,大概已经分析出原因了,就是redsocks2编译出来时调用动态库的,而redsocks是编译后是静态库,用file命令就你能看出来,不知道怎么把redsocks2也编译成静态库的,求指导

Avatar_small
依云 说:
Jun 04, 2014 03:11:04 PM

这个项目用的是 Makefile,你加 CFLAGS=-static 环境变量试试。
NDK 编译出来的动态链接版本应该一样好用的呀,只要把相应的库都放到系统上即可。

lxfan 说:
Jun 04, 2014 03:15:43 PM

我上午把提示出错的那个库放到手机里,然后就可以用了,正常使用了,谢谢依云的帮助,因为刚学linux,对很多都不是太懂,只能依靠教程,网上这个软件的教程太少了,不知道redsocks与ProxyDroid有什么区别,貌似ProxyDroid这个也是伪全局代理在案桌上,查了资料说redsocks才能在案桌上实现全局代理就试试编译用用了

lxfan 说:
Jun 09, 2014 06:21:23 PM

依云请教个问题,privoxy是不是只能用在网页的socks转换http,能不能设置对单独的客户端程序也能将socks转换http处理?找个好久没看到相关的方法。还有个问题,有没有在安卓上架设本地socks服务器的软件或者开源项目?

Avatar_small
λ 说:
Jun 09, 2014 06:26:23 PM

Privoxy 我知道。它无法得知 HTTP/HTTPS 网络请求的来源,只能是客户端主动通过指定端口利用 Privoxy 。假如软件没有自带代理配置功能,只能靠别的程序来中转网络请求了,例如 proxychains。

StarBrilliant 说:
Jun 09, 2014 06:35:46 PM

你可以试试 proxytunnel。它会把 HTTP CONNECT proxy 映射为标准输入输出。
可以配合 socat 用。

lxfan 说:
Jun 09, 2014 10:10:34 PM

我是用在移动cmwap接入点上的,因为移动cmwap开放的代理是10.0.0.172:80,自己先编译了redsocks后做全局代理,发现大部分问题解决,唯有qq,微信,还有游戏类的无法使用,估计这些软件应该是使用socks代理,打算在安卓上架设socks本地服务器(不知道用什么软件能架设),先将所有数据通过本地socks代理,在用Privoxy转化http交给10.0.0.172:80处理,不知道行的通吗?有其他解决方案吗?

Avatar_small
依云 说:
Jun 10, 2014 12:05:11 PM

QQ 不是用的 HTTP 啊。cmwap 那个只能用来访问 HTTP(S) 的。为什么不用 cmnet 呢?

lxfan 说:
Jun 10, 2014 01:51:57 PM

因为被移动限制了只能使用cmwap,只能http或者https,在电脑上可以解决问题,但是在安卓手机端暂时没找到解决qq,微信,游戏类正常使用的方法

Avatar_small
依云 说:
Jun 10, 2014 03:04:29 PM

那没办法。找移动去吧。

Smallville 说:
Jul 05, 2017 08:16:22 AM

仙子,请问你这个教程中$DNS_PORT应该填什么?搞不清,谢谢。
>>> sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:5353 0.0.0.0:* LISTEN 1/init
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 419/dnsmasq
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN 406/vsftpd
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 407/sshd
tcp 0 0 127.0.0.1:1080 0.0.0.0:* LISTEN 528/python2.7
tcp6 0 0 :::53 :::* LISTEN 419/dnsmasq
tcp6 0 0 :::22 :::* LISTEN 407/sshd

Avatar_small
依云 说:
Jul 05, 2017 10:52:00 PM

你本地起了干净的 dnsmasq 的话,就不需要再设置了。

Smallville 说:
Jul 05, 2017 11:42:00 PM

依云兄,之前我防火墙INPUT策略为DROP,总不成功,改为ACCEPT后可以了,谢谢。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com