共计 6171 个字符,预计需要花费 16 分钟才能阅读完成。
- BIND: 一个流行的域名解析服务器,我们可以设置哪些域名需要走加密线路。
- Stunnel: 使用 TLS 对 tcp 协议进行加密,也就是对 tcp 建立一条加密线路。
- SNI Proxy: 代理软件。对于 HTTP 协议,它可以根据 Host 请求头解析得出目标站 IP; 对于 HTTPS 协议,它可以根据 SNI 扩展中的域名解析得出目标站 IP。
优点:
无需手动设置任何代理,就能够自动加密代理特定网站的 HTTP 或 HTTPS 协议
相对于我们常用的 ssh 隧道,ssh 隧道是单路,而此方案是支持多并发连接,可以极大加速网站访问。
缺点:
对于代理 HTTPS 协议,需要发起 HTTPS 连接的客户端,比如浏览器支持 TLS 的 SNI 扩展。好消息是目前浏览器几乎都支持此扩展,但对于一些非浏览器的客户端,不支持 SNI 扩展。我们只能设置正向代理来解决此问题。
流程图:
原理介绍:
1、首先我们需要准备三台服务器,一台是内网 DNS 服务器(安装 bind),一台是内网代理服务器(安装 stunnel),另一台国外服务器(安装 stunnel,sniproxy)。
2、我们还需要设置 DNS 为内网的 DNS,并在内网 bind dns 设置谷歌域名解析的 IP 为内网代理服务器
3、当我们访问谷歌网站时,首先会向内网 DNS 服务器发送 DNS A 记录查询,此时内网 DNS 服务器会返回内网代理服务器的 IP。
4、浏览器得到谷歌域名的解析 IP 后(即内网代理服务器的 IP),会向内网代理服务器发送 HTTP 或 HTTPS 请求。
5、此时内网代理服务器(即 stunnel),会接收到请求,经过加密,把请求转发到国外服务器 (stunnel) 的指定端口上。
6、国外服务器 (stunnel) 接收到来自国内服务器 (stunnel) 的加密数据后,经过解密,把请求转发到 sniproxy。
7、sniproxy 再根据 HTTP Host 请求头或者 HTTPS sni 扩展的域名解析出谷歌服务器的 IP,并把请求转发给谷歌服务器。
8、谷歌服务器收到来自 sniproxy 发送的请求后,马上返回网页内容给 sniproxy,sniproxy 再原路返回数据给浏览器。
由于时间有限,我们仅在 Ubuntu server 12.04 演示安装。
系统:Ubuntu server 12.04
内网 DNS IP: 10.96.153.201(主),10.96.153.204(从)
内网代理服务器:10.96.153.204
国外服务器 IP: 1.2.3.4
1、在主 DNS 和从 DNS 安装 bind, 即 10.96.153.201(主),10.96.153.204(从)。
wget http://www.isc.org/downloads/file/bind-9-10-0b1-2/?version=tar.gz -O bind-9-10-0b1-2.tar.gz
tar xzf bind-9-10-0b1-2.tar.gz
cd bind-9-10-0b1-2
./configure --prefix=/usr/local/bind
make && make install
2、配置主 DNS 服务器(10.96.153.201)
2.1、生成 /usr/local/bind/etc/rndc.key 密钥文件
/usr/local/bind/sbin/rndc-confgen -a -k rndckey -c /usr/local/bind/etc/rndc.key
2.2、编辑 /usr/local/bind/etc/named.conf,写入如何内容:
include "/usr/local/bind/etc/rndc.key";
controls {inet 127.0.0.1 port 953 allow { 127.0.0.1;} keys {"rndckey";}; };
logging {channel default_syslog { syslog local2; severity notice;};
channel audit_log {file "/var/log/bind.log"; severity notice; print-time yes;};
category default {default_syslog;};
category general {default_syslog;};
category security {audit_log; default_syslog;};
category config {default_syslog;};
category resolver {audit_log;};
category xfer-in {audit_log;};
category xfer-out {audit_log;};
category notify {audit_log;};
category client {audit_log;};
category network {audit_log;};
category update {audit_log;};
category queries {audit_log;};
category lame-servers {audit_log;};
};
options {
directory "/usr/local/bind/etc";
pid-file "/usr/local/bind/var/run/bind.pid";
transfer-format many-answers;
interface-interval 0;
forward only;
forwarders {202.96.128.166;202.96.134.133;};
allow-query {any;};
};
zone "google.com" {
type master;
file "google.com.zone";
allow-transfer {10.96.153.204;};
};
在这个 named.conf 文件中,我们只需要关心如下内容:
对于 options{}区域,202.96.128.166 和 202.96.134.133 这两个是 ISP 提供的本地 DNS,需要修改为自己所在 ISP 的本地 DNS。
对于 zone“google.com”{}区域,这里定义了 google.com 域名的区域文件 google.com.zone,还有允许 10.96.153.204(即从 DNS)同步区域文件。
2.3、建立 google.com.zone 区域文件:
$TTL 3600
@ IN SOA ns1.google.com. hostmaster.google.com. (
2014072015 ; Serial
3600 ; Refresh
900 ; Retry
3600000 ; Expire
3600 ) ; Minimum
@ IN NS ns1.google.com.
@ IN NS ns2.google.com.
ns1 IN A 10.96.153.201
ns2 IN A 10.96.153.204
@ IN A 10.96.153.204
* IN A 10.96.153.204
对于这个区域文件:
ns1 IN A 10.96.153.201 指向第一个 dns 服务器,即主 DNS。
ns2 IN A 10.96.153.204 指向第二个 dns 服务器,即从 DNS。
@ IN A 10.96.153.204 和 * IN A 10.96.153.204 指向内网的代理服务器(stunnel)。我们只需要修改这三个地方就好了。
3、配置从 DNS 服务器(10.96.153.204)
编辑 named.conf,写入如下内容
logging {channel default_syslog { syslog local2; severity notice;};
channel audit_log {file "/var/log/bind.log"; severity notice; print-time yes;};
category default {default_syslog;};
category general {default_syslog;};
category security {audit_log; default_syslog;};
category config {default_syslog;};
category resolver {audit_log;};
category xfer-in {audit_log;};
category xfer-out {audit_log;};
category notify {audit_log;};
category client {audit_log;};
category network {audit_log;};
category update {audit_log;};
category queries {audit_log;};
category lame-servers {audit_log;};
};
options {
directory "/usr/local/bind/etc";
pid-file "/usr/local/bind/var/run/bind.pid";
transfer-format many-answers;
interface-interval 0;
forward only;
forwarders {202.96.128.166;202.96.134.133;};
allow-query {any;};
};
zone "google.com" {
type slave;
file "google.com.zone";
masters {10.96.153.201;};
};
配置从 DNS 就简单得多,只需要写入如上内容到 named.conf 文件。同样的,options{}中 202.96.128.166 和 202.96.134.133 这两个是当地 ISP 本地 dns。zone“google.com”{}中 10.96.153.201 指明主 DNS 服务器 IP。
4、启动 bind dns 服务器
/usr/local/bind/sbin/named
1、在内网代理服务器和国外主机安装 stunnel
apt-get install stunnel4
2、内网代理服务器 stunnel 配置
编辑 /etc/default/stunnel4,设置 ENABLED=1。
client = yes
pid = /etc/stunnel/stunnel.pid
[http]
accept = 80
connect = 1.2.3.4:8082
[https]
accept = 443
connect = 1.2.3.4:4433
此配置文件表示,监听了 80 端口,并把此端口流量转发到 1.2.3.4:8082,监听了 443 端口,并把此端口流量转发到 1.2.3.4:4433
3、国外服务器 stunnel 配置
3.1、生成 ssl 证书 stunnel.pem 文件
openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out cert.pem -days 1095
cat key.pem cert.pem >> /etc/stunnel/stunnel.pem
3.2、编辑 /etc/stunnel/stunnel.conf 文件
client = no
[http]
accept = 1.2.3.4:8082
connect = 127.0.0.1:8082
cert = /etc/stunnel/stunnel.pem
[https]
accept = 1.2.3.4:4433
connect = 127.0.0.1:4433
cert = /etc/stunnel/stunnel.pem
此配置文件表示,监听了 1.2.3.4:8082,并转发此地址流量到 127.0.0.1:8082,监听了 1.2.3.4:4433,并转发给地址流量到 127.0.0.1:4433。
3.3、编辑 /etc/default/stunnel4,设置 ENABLED=1。
4、启动 stunnel
service stunnel4 start
sniproxy 项目地址:https://github.com/dlundquist/sniproxy
1、安装 sniproxy
同样只演示在 ubuntu server 12.04 安装。
1.1、安装 UDNS
mkdir udns_packaging
cd udns_packaging
wget http://archive.ubuntu.com/ubuntu/pool/universe/u/udns/udns_0.4-1.dsc
wget http://archive.ubuntu.com/ubuntu/pool/universe/u/udns/udns_0.4.orig.tar.gz
wget http://archive.ubuntu.com/ubuntu/pool/universe/u/udns/udns_0.4-1.debian.tar.gz
tar xfz udns_0.4.orig.tar.gz
cd udns-0.4/
tar xfz ../udns_0.4-1.debian.tar.gz
dpkg-buildpackage
cd ..
dpkg -i *.deb
1.2、安装 sniproxy
apt-get install autotools-dev cdbs debhelper dh-autoreconf dpkg-dev gettext libev-dev libpcre3-dev libudns-dev pkg-config
wget https://github.com/dlundquist/sniproxy/archive/master.zip
unzip master.zip
cd sniproxy-master/
dpkg-buildpackage
cd ..
dpkg -i *.deb
2、配置 sniproxy
/etc/sniproxy.conf 内容如下:
user daemon
pidfile /var/run/sniproxy.pid
error_log {
syslog deamon
priority notice
}
listen 127.0.0.1:8082 {
proto http
table http_hosts
}
table http_hosts {.* *:80}
listen 127.0.0.1:4433 {
proto tls
table https_hosts
}
table https_hosts {.* *:443}
此配置文件表示,监听了 127.0.0.1:8082 地址,并解析 http 协议中的 Host 请求头为 IP,然后转发请求到此 IP; 监听了 127.0.0.1:4433 地址,并解析 TLS 中 SNI 扩展中的域名为 IP,并转发请求到此 IP。
3、启动 sniproxy
sniproxy
结束
到目前为止,我们已经搭建完成了整套 HTTP/HTTPS 加密代理方案。方案中的 HTTP 明文协议,利用 stunnel 使用了 TLS 加密,变成了 HTTPS 协议,使得数据包无法被解析出明文。方案中的 HTTPS 协议,本身是加密的,但为了防止 SNI 扩展的中域名被嗅探,还是走了 stunnel 的加密通道。对于发送 HTTPS 请求而不支持 SNI 扩展的客户端,需要手动设置下代理。