关于PAC自动代理和ios翻墙

通过这篇文章,你将了解以下几点:

  • HTTP代理
  • shadowsocks翻墙
  • PAC自动代理
  • PAC的编写规则
  • 防御端口扫描

 基本原理

HTTP代理即通过指定服务器代为请求网页信息,并将response返还给客户端。代理服务器在客户端和web服务器之间,扮演中间人的角色。按照使用场景划分有很多不同作用,这里我们用作翻墙。

通过在pac自动代理中指定HTTP代理服务器(也可以指定socks5代理,但部分客户端不支持),我们就可以在支持pac代理的客户端输入pac文件的url就可以愉快的翻墙了。

理想的方式是在国外直接架设一台HTTP代理服务器,然而事实并没有我们想的这么简单,因为HTTP代理并没有加密,所以会被GFW过滤掉。

这时候我们需要借助一台国内服务器和一台国外服务器,在两个服务器之间架设tunnel,流量加密穿过GFW。而国内服务器同时作为HTTP代理服务器,为国内设备提供代理服务。

我们来画图描述一下,一目了然。

这里的tunnel可以使用任何方式,包括但不限于:各种vpn(pptp/l2tp/open/shadow/anyconnet/ipsec),各种tunnel(曲径使用的qtunnel/gotunnel),以及本文使用的shadowsocks。

 自动代理

Pac叫Proxy auto-config,是一个用来自动代理的技术,一个PAC文件包含一个JavaScript形式的函数,定义了一系列访问规则,用户代理根据这些规则适用一个特定的代理其或者直接访问。简单来说,就是指定一部分域名和相应的代理方式,于是我们可以定义一些被GFW block的域名来指定http代理或者socks5代理,而未被block的域名直接访问就可以了。这叫智能分流,比VPN的全局翻墙更智能快速。

对于windows/linux/android/mac os等客户端可以直接使用shadowsocks,但是未越狱的iOS则无法使用,好在iOS支持pac自动代理,于是我们可以搭建一个http代理服务器,再配合pac文件就可以智能分流翻墙了。

 shadowsocks

shadowsocks是一个可穿透防火墙的快速代理。通过客户端以指定的密码、加密方式和端口连接服务器,成功连接到服务器后,客户端在用户的电脑上构建一个本地socks5代理。使用时将流量分到本地socks5代理,客户端将自动加密并转发流量到服务器,服务器以同样的加密方式将流量回传给客户端,以此实现代理上网。

这里shadowsocks的客户端是国内服务器,shadowsocks的服务器就是国外服务器。

 转换、缓存和安全

shadowsocks提供了socks5代理,我们需要在国内服务器上将其转换成HTTP代理,polipo很方便的实现了该功能,并且提供了缓存的功能用于加速。除此之外,由于PAC不支持http basic认证,所以为了安全,我们需要在国内服务器上防止端口扫描,防止有坏(无聊的)人恶意扫描端口、使用代理。

 详细过程

 shadowsocks服务端

在境外服务器A上:

 安装

Debian / Ubuntu:

1
2
apt-get install python-pip
pip install shadowsocks

CentOS:

1
2
yum install python-setuptools && easy_install pip
pip install shadowsocks

 使用

新建配置文件/etc/shadowsocks.json

1
2
3
4
5
6
7
8
9
10
11
12
{
"server":"157.7.7.7", # 服务器监听地址,可以0.0.0.0
"port_password": {
"1001": "pass1",
"1002": "pass2",
"1003": "pass3" # 可以分配为不同端口指定不同密码
},
"local_address": "127.0.0.1",
"local_port":1080,
"timeout":300,
"method":"rc4-md5" # 加密方式,此种适合在openwrt路由器上使用,兼具轻量级和安全性
}

运行

1
2
useradd -M ssuser
ssserver -c /etc/shadowsocks.json --user ssuser -d start

更多优化和配置请参考官方wiki

 shadowsocks客户端

在国内服务器B上,使用如下命令来运行

sslocal -s 157.7.7.7 -p 1001 -k pass1 -m rc4-md5 -b 0.0.0.0 -l 8888 -d start

这样B服务器就开始监听8888端口的socks5代理。

对于SwitchyOmega等代理插件是支持PAC中指定socks5代理,但是IE并不支持,iOS未测试。不过为了优化代理,我们可以通过polipo来将socks5代理转换为http代理,更重要的是polipo支持缓存。

Polipo is a caching HTTP proxy that was originally designed as a personal proxy, i.e. a proxy
that is used by a single user or a small group of users. However, it has successfully been used
by larger groups.

 HTTP缓存代理polipo

安装直接 yum install polipo
配置文件 /etc/polipo/config

在配置文件中新增以下内容

1
2
3
4
5
6
logSyslog = true
logFile = /var/log/polipo/polipo.log # 指定日志
proxyAddress = "0.0.0.0" # 监听地址
proxyPort = 10001 # 监听端口
socksParentProxy = "localhost:8888" # 指定一级代理为本地的8888
socksProxyType = socks5 # 代理类型为socks5

启动 service polipo start

对于polipo的更多优化和配置请参考官方manual

 PAC文件

一个PAC文件是一个至少定义了一个JavaScript函数的文本文件。这个函数FindProxyForURL(url, host)有2个参数:url是一个对象的URL,host是一个由这个URL所派生的主机名。按照惯例,这个文件名字一般是proxy.pac. WPAD标准使用wpad.dat。

一个最简单的PAC文件内容如下:

1
function FindProxyForURL(url, host) { return "PROXY proxy.example.com:8080; DIRECT"; }

 

指定所有流量都通过proxy.example.com的8080端口来进行http代理。

一个稍微复杂点的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
function FindProxyForURL(url, host) {
// 本地域名不进行代理,直接访问:
if (shExpMatch(url,"*.example.com/*")) {return "DIRECT";}
if (shExpMatch(url, "*.example.com:*/*")) {return "DIRECT";}
 
// URL在这个网络范围内时进行HTTP代理
if (isInNet(host, "10.0.0.0", "255.255.248.0")) {
return "PROXY fastproxy.example.com:8080";
}
 
// 其他流量进行代理,如果失败则直连
return "PROXY proxy.example.com:8080; DIRECT";
}

 

如果需要socks5代理,则将PROXY改成SOCKS

这里提供我使用的pac文件供大家参考,可以使用gfwlist2pac这个工具来将gfwlist转换成pac。

  

在最后面我提供了我使用的PAC文件,你只需要修改var proxy = 'PROXY myproxy.com:10001;';这一行的内容就可以了。

再提供几个函数,大家可以自行研究并参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//判断IP是否合法
function checkip(host) {
var ipValidate=/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
if (ipValidate.test(host)) {
return true;
}
else {
return false;
}
}
 
//匹配特定域名
function DomainProxy(url, host) {
if (
shExpMatch(host, "tc.dlservice.microsoft.com") ||
shExpMatch(host, "qh.dlservice.microsoft.com") ||
shExpMatch(host, "download.microsoft.com")
)
return 1;
else
return 0;
}
//匹配内网IP
function IpDirect(url, host) {
if (
isInNet(host, "10.0.0.0", "255.0.0.0") ||
isInNet(host, "127.0.0.0", "255.255.255.0") ||
isInNet(host, "172.0.0.0", "255.0.0.0") ||
isInNet(host, "172.16.0.0", "255.240.0.0") ||
isInNet(host, "192.168.0.0", "255.255.0.0")
)
return 1;
else
return 0;
}
 
function FindProxyForURL(url, host) {
//基于IP判断出口
if(checkip(host)) {
if(IpDirect(url, host)) {
return "DIRECT";
}
else
return "PROXY myproxy.example.com:8080";
}
//基于域名判断出口
else{
if(DomainByProxy(url, host)) {
return "PROXY myproxy.example.com:8080";
}
else if(DomainDirect(url, host)) {
return "DIRECT";
}
else if(DomainHKProxy(url, host)) {
return "PROXY hk.myproxy.com:8080";
}
else if(DomainProxy(url, host)) {
return "PROXY proxy.example.com:8080";
}
else
return "PROXY web-proxy.example.com:8080";
}
}

 配置

PAC文件配置完成以后可以上传到你的web server或者OSS这样的云存储,我们假设url为https://example.com/proxy.pac

 iOS

step 1
step 2

 Android

可以安装ProxyDroid,在自动代理地址栏中输入pac的url。

 Mac

  • 依次进入「设置」->「网络」->「Wi-Fi」(或「以太网」);
  • 点击「高级」->「代理」;
  • 选中「自动代理配置」,然后将PAC url输入在「代理配置文件」一栏:
  • 点击「好」->「应用」;

 Windows 10

  • 打开设置
  • 「网络和Internet」->「代理」
  • 点击打开「使用安装程序脚本」,在「脚本地址」处写入pac的url。
  • 点击「保存」

 Windows 7

  • 启动Internet Explorer浏览器
  • 依次进入「工具「->「互联网选项」->「连接」;
  • 如果你用当前电脑拨号连接,选中此拨号连接,然后点旁边的「设置」;
  • 如果你用路由器,或者你的电脑通过局域网上网,选择「局域网设置」
  • 选中「使用自动配置脚本」,然后将PAC url输入在「地址」一栏:
  • 一路点击「确定」;

 Chrome/Firefox

  • 下载SwitchyOmega
  • 安装:将SwitchyOmega.crx拖入chrome
  • 打开选项
  • 新建情景模式
  • 情景模式名称随便写,选择PAC情景模式,在PAC网址中输入pac的url,或者在下方的PAC脚本中将pac内容粘贴至内。

 WPAD

WPAD(web-proxy auto discovery)技术可以使用dhcp/dns来实现自动发现代理。这个我们以后再谈,一般用在企业中实现客户端代理自动部署。

 端口扫描和加密

polipo支持http basic authentication,但是PAC是个js语法的文件并不支持用户名和密码认证,这就很蛋疼。
如果有人在扫描你的端口,那你就很难逃脱。

所以干脆来防止端口扫描吧。

portsentry有几种工作模式,其中的的高级隐秘模式可以监听所有未占用端口,一旦发现有人试图连接这些端口,如果超过阈值,则会采取行动,所以前提是iptables没有DROP这些端口。采取的措施包括:

  • 在/etc/hosts.deny中加入 ALL: 113.144.244.107这样的条目来block掉所有能访问的服务
  • 或者更狠,直接route del -host 14.17.92.11 reject 丢弃指定IP的路由
  • 可以使用自定义的脚本去处理

对于白名单我们可以记录在portsentry.ignore这个文件中
自定义脚本可以在配置文件中使用KILL_RUN_CMD="/log-portsentry.sh $TARGET$ $PORT$"来处理
SCAN_TRIGGER="3" 可以指定触发block的阈值

启动

1
2
/usr/local/psionic/portsentry/portsentry -atcp
/usr/local/psionic/portsentry/portsentry -audp

 

更多配置请自行参考portsentry的配置文件。

 PAC实例

覆盖大部分大陆不能访问的网址 :)

相关帖子:http://briteming.hatenablog.com/entry/2018/08/12/195922