TLS SNI Proxy/无需证书的反向代理

English Version

1. Principle

RFC4366 defines the server name indication extension for TLS. Using this we can construct a TCP proxy that detects server name in the client handshake and proxies to the appropriate HTTPS server. This has the advantage over Nginx or Apache HTTPS SNI virtual hosting that the proxy does not need to the servers private key. This could be useful as we exhaust IPv4 addresses and HTTPS virtual hosting becomes necessary: a proxy could listen on an IPv4 address and proxy to HTTPS servers on separate IPv6 addresses.

2. Features

  • Name-based proxying of HTTPS without decrypting traffic. No keys or certificates required.
  • Supports both TLS and HTTP protocols.
  • Supports IPv4, IPv6 and Unix domain sockets for both back end servers and listeners.
  • Supports multiple listening sockets per instance.

Because it is based on sni, so if the site does not support https, you can not use sniproxy proxy to proxy.

3. Installation

I. CentOS/Fedora/RedHat

# sudo yum install autoconf automake curl gettext-devel libev-devel pcre-devel perl pkgconfig rpm-build udns-devel
# git clone https://github.com/dlundquist/sniproxy
# cd sniproxy
# ./autogen.sh && ./configure && make dist
# rpmbuild --define "_sourcedir `pwd`" -ba redhat/sniproxy.spec
# sudo yum install ../sniproxy-<version>.<arch>.rpm

II. Debian/Ubuntu

# sudo apt-get install autotools-dev cdbs debhelper dh-autoreconf dpkg-dev gettext libev-dev libpcre3-dev libudns-dev pkg-config fakeroot devscripts
# git clone https://github.com/dlundquist/sniproxy
# cd sniproxy
# ./autogen.sh && dpkg-buildpackage
# sudo dpkg -i ../sniproxy_<version>_<arch>.deb

or

# apt-get install python-software-properties
# add-apt-repository ppa:dlundquist/sniproxy
# apt-get update && apt-get install sniproxy

4. Configuration

user daemon

pidfile /tmp/sniproxy.pid

error_log {
    syslog daemon
    priority notice
}

listener 127.0.0.1:443 {
    protocol tls
    table TableName

    # Specify a server to use if the initial client request doesn't contain
    # a hostname
    fallback 192.0.2.5:443
}

table TableName {
    # Match exact request hostnames
    example.com 192.0.2.10:4343
    # If port is not specified the listener port will be used
    example.net [2001:DB8::1:10]
    # Or use regular expression to match
    .*\\.com    [2001:DB8::1:11]:443
    # Combining regular expression and wildcard will resolve the hostname
    # client requested and proxy to it
    .*\\.edu    *:443
}

In IPv4,you need to specify to listen the external network address ( 127.0.0.1 replacement), otherwise it will only listen to the IPv6.

5. Running

Use the command 'sniproxy' to run directly,The default configuration file, /etc/sniproxy.conf, will be loaded automatically. If you use a different path or configuration file name, you will need to use the -c option to specify the path:

# sniproxy -c /etc/sniproxy.conf

6. Redirection

Generally,we does not like to enter the port number or protocol name when visit the site, but the default visit is the 80 port how we to do? As a supplement, we installed nginx, let it transfer all the 80 port traffic to 443 port, we can use 301 redirect.

Note that for Google and other special domain name, it may be can't jump even if you do a port redirect, because GFW can unpack HTTP traffic。

# vim /etc/nginx/sites-available/default
  server {
        listen   80;
        #listen   [::]:80 default ipv6only=on;

        server_name _;
 
        location / {
                rewrite ^ https://$host$request_uri permanent;
        }
  }

7.Usage

sniproxy builded successfully, but it can not be directly accessed, we need to resolve the domain name, so that it can be to your ssl site based on the domain name, you may need to modify their own hosts.
However, another easier way is to use dnsmasq, this later to say.

中文版

一、原理

RFC4366 定义了 TLS 的服务器名称指示扩展。利用这一点,我们可以构建一个 TCP 代理,用于检测客户端握手中的服务器名称并将其代理到相应的 HTTPS 服务器。这与 Nginx 或 Apache HTTPS SNI 虚拟主机相比,该代理不需要服务器私钥。这对于当前已经用尽 IPv4 地址和 HTTPS 变成必要的环境下是非常有用的:代理可以侦听 IPv4 地址,以及代理到在单独的 IPv6 地址上运行的 HTTPS 服务器。

二、功能

  • 基于名称的代理 HTTPS,无需解密流量,不需要密钥或证书。
  • 支持 TLS 和 HTTP 协议。
  • 支持后端服务器和监听器的 IPv4,IPv6 和 Unix 域套接字。
  • 支持多个监听套接字。

当然了,既然是基于 sni 技术,那 http 页面是肯定不能代理的,如果目标网站不支持 https,就不不能使用 sniproxy 做代理了。

三、安装

1、CentOS/Fedora/RedHat

# sudo yum install autoconf automake curl gettext-devel libev-devel pcre-devel perl pkgconfig rpm-build udns-devel
# git clone https://github.com/dlundquist/sniproxy
# cd sniproxy
# ./autogen.sh && ./configure && make dist
# rpmbuild --define "_sourcedir `pwd`" -ba redhat/sniproxy.spec
# sudo yum install ../sniproxy-<version>.<arch>.rpm

2、Debian/Ubuntu

# sudo apt-get install autotools-dev cdbs debhelper dh-autoreconf dpkg-dev gettext libev-dev libpcre3-dev libudns-dev pkg-config fakeroot devscripts
# git clone https://github.com/dlundquist/sniproxy
# cd sniproxy
# ./autogen.sh && dpkg-buildpackage
# sudo dpkg -i ../sniproxy_<version>_<arch>.deb

或者

# apt-get install python-software-properties
# add-apt-repository ppa:dlundquist/sniproxy
# apt-get update && apt-get install sniproxy

四、配置

user daemon

pidfile /tmp/sniproxy.pid

error_log {
    syslog daemon
    priority notice
}

listener 127.0.0.1:443 {
    protocol tls
    table TableName

    # Specify a server to use if the initial client request doesn't contain
    # a hostname
    fallback 192.0.2.5:443
}

table TableName {
    # Match exact request hostnames
    example.com 192.0.2.10:4343
    # If port is not specified the listener port will be used
    example.net [2001:DB8::1:10]
    # Or use regular expression to match
    .*\\.com    [2001:DB8::1:11]:443
    # Combining regular expression and wildcard will resolve the hostname
    # client requested and proxy to it
    .*\\.edu    *:443
}

对于 IPv4 来讲,你需要明确地写出要监听的外网地址(将代码中的 127.0.0.1 替换),否则就会只监听 IPv6 了。

五、运行

直接使用命令sniproxy 即可运行,默认配置文件 /etc/sniproxy.conf 会自动加载,如果你使用了其他路径或者配置文件名,那么你需要使用 -c 选项来指定路径:

# sniproxy -c /etc/sniproxy.conf

六、端口重定向

一般我们访问网站不喜欢输入端口号或者协议名称,那么默认访问的是 80 端口怎么办?作为辅助,我们安装一个轻量级的 nginx,让它把所有访问 80 端口的流量转移到 443 上边去,使用 301 重定向即可。

注意,针对 Google 等特殊域名,可能即使你做了端口重定向也无法跳转解析,是因为 GFW 能够解包 HTTP 流量。

# vim /etc/nginx/sites-available/default
  server {
        listen   80;
        #listen   [::]:80 default ipv6only=on;

        server_name _;
 
        location / {
                rewrite ^ https://$host$request_uri permanent;
        }
  }

七、使用

sniproxy 搭建成功,但是它是不能被直接访问的,你需要将域名解析过去,这样它才能根据域名来代理你的 ssl 链接,那么你可能就需要修改自己的 hosts 解析。
不过,另外一个更简便的办法是使用 dnsmasq,这个以后再说。


References / 参考文章:

  1. GitHub: dlunduist/sniproxy
  2. 一个 反代无需证书 适用于DNS/Hosts的小工具 —— SNI Proxy代理 安装教程
  3. 部署 SNI Proxy 加速网页访问 反代 无需证书

ArmxMod for Typecho
个性化、自适应、功能强大的响应式主题

推广

 继续浏览关于 代理sniproxydns反向代理 的文章

 本文最后更新于 2017/10/30 18:55:50,可能因经年累月而与现状有所差异

 引用转载请注明:VirCloud's Blog > 运维 > TLS SNI Proxy/无需证书的反向代理

精选评论

  1. OwenSS

    如出现“error: couldn't find library”错误,请执行:
    echo /usr/lib/x86_64-linux-gnu > /etc/ld.so.conf
    echo /lib/x86_64-linux-gnu > /etc/ld.so.conf

    1. OwenSS

      以及 ldconfig 重新加载库