VPS的Netflix IP解锁服务自制版

  • By 毕勤
  • Sat 01 December 2018

需求的起源

最近已经基本上把看片的平台转移到Netflix了,确实节省了很多下片找片的时间,而且,不考虑防火墙和代理的问题下,这好歹是正版的付费看片。鉴于中国的现状,看Netflix翻墙是必须的,而且还挑梯子,Netflix基本上把大厂的IP都给列入封锁列表了,指望用Google Cloud搭酸酸乳看Netflix是个比较遥远的梦想。

最近在某VPS服务商那里看到他们提供一个Netflix IP解锁服务,也就是说让那些本来不能播放Netflix的VPS,通过他们的服务可以播放指定区域的VPS。刚开始我脑子一抽还以为他们能把数据中心的IP变成家庭宽带的IP来骗过Netflix,后来闻了一下需要提供VPS的root密码来让他们设置,我一看这不就是个代理服务吗?

其实这个也挺好的,因为在墙外的VPS之间,也就是数据中心之前其实速度还是很快的,基本上不用担心带宽不足延迟太大或者速度不稳定这些问题,即使经过一次转发,也不太影响使用体验。

否定的第一套方案

最开始的方案基本上就是靠着Google搜Netflix Proxy找到的,简单的说就是在可以看Netflix的VPS A上搭一个TCP反代,在VPS B上用dnsmasq之类的工具劫持DNS解析,把Netflix的相关域名都解析到VPS A上,这样VPS B就可以借用A的反代来访问Netflix了。 废话不多少直接上代码,VPS A上安装sniproxy,配置如下:

user nobody
resolver {
    nameserver 8.8.8.8
    mode ipv4_only
}

listen 0.0.0.0:443 {
proto tls
table https_hosts
access_log {
  filename /var/log/https_access.log
  priority notice
 }
}

table https_hosts {
    (.*.|)netflix.com$ *
    (.*.|)netflix.net$ *
    (.*.|)nflxext.com$ *
    (.*.|)nflxso.net$ *
    (.*.|)nflximg.net$ *
    (.*.|)nflxvideo.net$ *
}

VPS B上安装dnsmasq,配置如下:

no-resolv
no-poll
server=1.1.1.1
address=/netflix.com/18.215.191.191
address=/nflxext.com/18.215.191.191
address=/nflximg.net/18.215.191.191
address=/nflxext.com/18.215.191.191
address=/nflxso.net/18.215.191.191
address=/nflxvideo.net/18.215.191.191

这种方案之所以被否定,是因为本质上依赖DNS劫持。你可以劫持VPS B本身的DNS解析,但你在VPS B上搭建梯子后,你并没有办法劫持连上这个梯子的用户的DNS。所以用户还是会经过VPS B的代理,但访问原始的Netflix服务器,最终导致播放失败。

新方案

其实我把问题想得太复杂了,这不就是普通的透明代理转发吗?shadowsocks(R)就可以实现啊,只不过两台墙外的VPS用加密代理实在是浪费CPU资源,普通的代理就足够了。所以我决定在VPS A用Tinyproxy架设https代理,然后在VPS B用redsocks转成透明代理然后转发。

架设Tinyproxy Https代理

其实很简单,直接apt-get install tinyproxy就可以了。设置上我也几乎没有修改,仅仅是添加了一个Allow语句,给VPS B的IP放行,否则是无法使用的。而且这样默认也屏蔽了其他IP的访问,避免了变成冤大头。 最后的配置如下:

User tinyproxy
Group tinyproxy
Port 8888
Timeout 600
DefaultErrorFile "/usr/share/tinyproxy/default.html"
StatFile "/usr/share/tinyproxy/stats.html"
Logfile "/var/log/tinyproxy/tinyproxy.log"
LogLevel Info
PidFile "/run/tinyproxy/tinyproxy.pid"
MaxClients 100
MinSpareServers 5
MaxSpareServers 20
StartServers 10
MaxRequestsPerChild 0
Allow 127.0.0.1
Allow YOUR_VPS_B_IP
ViaProxyName "tinyproxy"
ConnectPort 443
ConnectPort 563

架设Redsocks代理

也是直接apt-get install redsocks,配置中只需要设置好https代理的IP和端口就行,记得https代理的类型是填http-connect。

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

    // info: start and end of client session
    log_info = on;

    /* possible `log' values are:
     *   stderr
     *   "file:/path/to/file"
     *   syslog:FACILITY  facility is any of "daemon", "local0"..."local7"
     */
    log = "syslog:daemon";

    // detach from console
    daemon = on;

    /* Change uid, gid and root directory, these options require root
     * privilegies on startup.
     * Note, your chroot may requre /etc/localtime if you write log to syslog.
     * Log is opened before chroot & uid changing.
     */
    user = redsocks;
    group = redsocks;
    // chroot = "/var/chroot";

    /* possible `redirector' values are:
     *   iptables   - for Linux
     *   ipf        - for FreeBSD
     *   pf         - for OpenBSD
     *   generic    - some generic redirector that MAY work
     */
    redirector = iptables;
}

redsocks {
    /* `local_ip' defaults to 127.0.0.1 for security reasons,
     * use 0.0.0.0 if you want to listen on every interface.
     * `local_*' are used as port to redirect to.
     */
    local_ip = 127.0.0.1;
    local_port = 12345;

    // `ip' and `port' are IP and tcp-port of proxy-server
    // You can also use hostname instead of IP, only one (random)
    // address of multihomed host will be used.
    ip = YOUR_VPS_A_IP; 
    port = 8888;


    // known types: socks4, socks5, http-connect, http-relay
    type = http-connect;

    // login = "foobar";
    // password = "baz";
}

然后配置iptables,先建立一个REDSOCKS链:

iptables -t nat -N REDSOCKS

这里有两套思路进行转发,一套是找出Netflix所有的IP地址,然后添加到REDSOCKS链,例如:

iptables -t nat -A OUTPUT -d 198.38.0.0/16 -j REDSOCKS

但问题是Netflix使用了akamai的CDN服务器,IP地址范围是在太大了,我已经把Netflix整个AS的地址都添加了也还是会提示在使用proxy。

干脆暴力点,直接把所有https流量都添加进去:

iptables -t nat -A OUTPUT -p tcp --dport 443 -j REDSOCKS

最后,转发到redsocks的透明代理端口:

iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345

最后记得用iptables-persistent之类的工具保存一下iptables规则,这样不论是从VPS B本机访问,还是透过VPS B上的代理,最后Netflix的HTTPS流量都会通过VPS A访问,而Netflix是全Https的,所以http部分我们不需要关心。

更小的IP范围

全部转发可能还是太暴力了,简单一点的做法是转发Netflix所有的IP和AWS所有的IP(因为当前Netflix有很多服务是架设在AWS上的)。

Netflix的IP可以在这里查到,而AWS的IP可以在这里看到,然后把这些IP范围分别添加到两个IPSET中,我把它们分别命名为aws和netflix。

ipset create aws hash:net
ipset create netflix hash:net

怎么转成命令我就懒得写了,这里有现成的脚本。

然后,把这两个IPSET里IP的443端口目标流量全部转发到REDSOCKS的透明代理上。

iptables -t nat -A PREROUTING -p tcp --dport 443 -m set --match-set aws dst -j REDIRECT --to-ports 12345
iptables -t nat -A PREROUTING -p tcp --dport 443 -m set --match-set netflix dst -j REDIRECT --to-ports 12345
iptables -t nat -A OUTPUT -p tcp --dport 443 -m set --match-set aws dst -j REDIRECT --to-ports 12345
iptables -t nat -A OUTPUT -p tcp --dport 443 -m set --match-set netflix dst -j REDIRECT --to-ports 12345

可能的问题: 你的代理服务器本身就是AWS服务器,这个就比较尴尬了,自己添加一个排除规则吧,其实AWS的服务器就算能看Netflix也是暂时的,早晚被封。 重启后ipset丢失,这是个问题,我目前也不知道有什么更优雅的方式来解决,简单点可以在启动项里重写ipset。