科学上网

Posted by wsxq2 on 2019-07-07
TAGS:  VPSGFWproxysshshadowsocksshadowsocksrV2Ray代理科学上网

本文最后一次编辑时间:2020-06-22 16:07:46 +0800

本文说明:本文最初写的是在 Kali Linux 中如何实现科学上网(只讲解了客户端的操作),但是后来压根儿就没怎么用 Kali Linux 了,而且发现科学上网这块内容是真的复杂,只讲解客户端的操作非常不完整。由于随着时间的推移,对科学上网的了解也逐渐增加,于是萌生了一个大胆的想法——从头梳理一下科学上网的知识。于是便有了本文

温馨提示:对于文中的维基百科链接,建议好好读一下,尤其是相应的英文页面,内容超级丰富,满满的干货

众所周知,科学上网是每个学计算机的人员的必备技能。本文从科学上网的基本概念开始,简要讲解科学上网的各种方法以及相关的原理。

概述

本部分主要讲述“翻墙”和“墙”的真正含义以及为什么要翻墙。其中“翻墙”和“墙”的定义均引用自“万能”的维基百科,强烈建议概览一下相关的维基百科页面,会让你受益匪浅;为什么要翻墙部分则是我的个人理解,欢迎大家补充

何为翻墙(科学上网)?

突破网络审查或突破网络封锁,俗称翻墙、穿墙、爬墙、科学上网、魔法上网、爱国上网、自由上网、正常上网等。由于“翻墙”在中国大陆境内成为敏感词汇,现在更多的使用科学上网来代替“翻墙”,通常特指在中国大陆绕过互联网审查封锁技术(IP封锁、端口封锁、关键词过滤、域名劫持等),突破防火长城,实现对网络内容的访问。

突破网络审查的软件通常被称作翻墙软件,俗称梯子。翻墙软件并不只是VPN、代理软件。它们着眼于获得被屏蔽的网站内容,并在访问受限网站时向ISP隐藏自己的真实地址信息。

——引用自突破网络审查 - 维基百科,自由的百科全书

何为墙?

防火长城[1](英语:Great Firewall,常用简称:GFW,中文也称中国国家防火墙[2],中国大陆民众俗称墙、防火墙、功夫网[3]等等),是对中华人民共和国政府在其互联网边界审查系统(包括相关行政审查系统)的统称。此系统起步于1998年[4],其英文名称得自于2002年5月17日Charles R. Smith所写的一篇关于中国网络审查的文章《The Great Firewall of China》[5],取与Great Wall(长城)相谐的效果,简写为Great Firewall,缩写GFW[6]。随着使用的拓广,中文“墙”和英文“GFW”有时也被用作动词,网友所说的“被墙”即指网站内容被防火长城所屏蔽或者指服务器的通讯被封阻,“翻墙”也被引申为突破网络审查浏览境内外被屏蔽的网站或使用服务的行为。

——引用自防火长城 - 维基百科,自由的百科全书

为什么要翻墙?

有人常常问我翻墙有什么好处,为什么要翻墙,现我将其总结如下:

  • 搜索引擎:作为搞机人员最重要的工具,国外的 Google 比国内的 百度 好用得不要太多。
  • 维基百科:比国内的百度百科等更客观,更合理,更准确。其底蕴(维基百科推出时间 2001 年,百度百科 2006 年)是国内任何百科都无法比拟的。详情参见 维基百科 - 维基百科,自由的百科全书百度百科 - 维基百科,自由的百科全书
  • GitHub:作为全球最大的“同性交友网站”(大误),这是一个开发者流连忘返的地方,然而在国内时而能访问,时而不能访问
  • 问答网站:如 Stack Overflow比国内百度大力推荐的百度知道靠谱得不要太多。
  • 官方网站:很多好的软件的官网都在国外,如 Windows,Ubuntu,Kali Linux,CentOS,VirtualBox,7zip,Java,Google Chrome等,在国内访问它们要么访问很慢要么完全无法访问
  • 学习环境:国内不少论坛贴吧等交流网站日常进行着无意义的争辩,且常有学到一点东西就得意忘形的人在其中炫耀,少有技术干货。
  • “翻墙”与“墙”的博弈的趣味性:在学习“翻墙”和“墙”的过程可以收获大量知识
  • ……

方法

既然知道了是什么和为什么,那么接下来便是怎么做了。本部分简要阐述现今(2019-07-01)常用的方法。

方法可粗略地分为免费付费两大部分,其中由于免费的方法大多存在各种问题,所以只是简单地提一下,而付费的方法则是重点阐述的对象。

付费方法中又大体分为使用“机场”使用 VPS 自己搭建代理服务器这两种方法,前者没有技术难度,故只是简单提一下,而后者则难度较大,其中涉及的内容也较多,是本文的核心内容。也正因为后者内容较多,所以在这里的内容只是一个概述,后文会详细讲解

当然,由于翻墙技术的复杂性和不宜公开性,这里的方法可能只是冰山一角。

免费

  • 网上找免费的 VPNSSSSR 账号
  • 使用免费工具。如蓝灯(Lantern)等
  • 网上查找免费的 SSR 订阅
  • 免费蹭好友的 VPS

付费

“机场”

购买 VPN, SS, SSR 账号,也被称为“机场”。比较便宜的推荐如下:

  • yizhihongxing(需要科学上网):我最初科学上网时用得便是它,毕竟那个时候啥也不会。99¥/年。当时的使用体验还可以,现在不知道如何

    2020-06-19 更新:之前一支红杏失效了很长一段时间,现在全部改为 trojan 了,但使用体验并不是很好

  • justmysocks:亲测好用。237¥/年

    目前只有三个方案可选,支持月/季/半年/年付,付款周期越长价格越便宜,年付只需付10个月,目前支持paypal和支付宝付款,带宽分1G/2.5G/5G,对于GIA来说带宽相当大了。

    方案 流量/设备数 带宽 优惠码(5.2%) 价格 购买链接
    Just My Socks 100 100G/月 3台设备 GIA 1G JMS9272283 2.88$/月 点击购买
    Just My Socks 500 500G/月 5台设备 GIA 2.5G JMS9272283 5.88$/月 点击购买
    Just My Socks 1000 1000G/月 无限设备 GIA 5G JMS9272283 9.88$/月 点击购买

    ——引用自好用的机场推荐 | Atrandys

    常用链接:

  • 其他:

    • 次元链接(SS, SSR, V2RAY)
    • NordVPN(VPN
    • 喵帕斯(SSR, V2RAY)
    • YoYu(缺货)
    • 泡芙
    • 布丁
    • 东方网络
    • PoiCloud
    • dlercloud
    • ssrcloud

    来自 http://backu9.blogspot.com/2018/09/ssssr_18.html

    • 心阶云

    来自 https://3nice.cc/2019/04/07/xinjiecloud/

    • bywave
    • blinkload
    • duangcloud
    • 蓝岸
    • MEET

    来自 https://www.iszy.cc/2019/01/03/sci-conn/

    • ssrpass

VPS

自己租用 VPS 搭建代理服务器。

VPS 提供商
  • 搬瓦工:笔者一直用的它,它价格便宜(笔者当时的是200元/年左右)、速度较快(200KB/s+),但是延迟较高(200ms左右)。近期(2019-06-19)搬瓦工的大量 VPS IP地址被封,笔者就是其中的一员,但是亲测可以通过套 cf(cloudflare) 的方法继续使用。

    常用链接:

  • vultr:曾经尝试过使用它,但是其 IP 地址大多被封(因为我试了好几个节点就没有一个成功的 :joy:),于是就放弃了
  • virmach:一个好友用过,价格也比较便宜(200元/年),但是速度较慢(20Mbps 带宽下20KB/s)、延迟较高(376ms)。以上是我的测试,我的好友的测试结果和我截然相反,他那边速度较快(100Mbps 带宽下1MB/s)、延迟较低(250ms左右)
  • 其他:
    • 价格一般的:Linode Hostinger Kamatera hostwinds intersever Severpoint(colossuscloud) contabo I/O Zoom DO sugarhosts AWS。
    • 便宜的:onevps buyvm hostflyte virmach anynode(hostigation)、anynode-bill fantech raksmart。

    以上 VPS 笔者都没有用过,但是是笔者精心整理的,仅供参考。上述 VPS 的整理参考了如下链接:

    • https://www.10besty.com/best-vps-hosting-services/
    • https://www.laozuo.org/myvps
    • https://www.zhujiceping.com/vps
使用的方案

本部分是本文的核心纲要,通过点击相应的方案链接可直接跳转到本文的相应位置。

这里所谓的方案其实实质都是一样的,那便是代理,因为从租用 VPS 的那一刻起,便走上了使用代理的道路

以下方案按出现时间排序(笔者推测的,如有错误欢迎留言)。关于 GFW 的发展史,可参见 道高一尺,墙高一丈:互联网封锁是如何升级的|大陆|互联网审查|端传媒Initium Media

  • 通用代理服务器:起初 GFW 没有现在这么强大的时候,大家可以通过简单的通用代理服务器上网。这里的通用代理服务器指的是 HTTP 代理服务器和 SOCKS 代理服务器。其中 HTTP 代理服务器最为常用。

    虽然该方案对于现今的 GFW 已经没有作用,但其原理和相关协议(例如 socks5 )依然在使用。比如大家熟知的 SS 便在本地主机上搭建了一个 SOCKS 代理服务器(监听地址通常为127.0.0.1 1080)。

    后文将会花不少篇幅讲解这方面的内容

  • SSH-D参数:使用 OpenSSH 软件包中ssh命令的 -D 参数即可实现科学上网。该方法的前提是你可以通过 SSH 成功连上你的服务器,且你的服务器能访问国外网站(如谷歌等)。优点在于简单方便,缺点在于不适合多人使用,且可能易被 GFW 识别。

  • VPN:未曾尝试过。请自行研究。后面有空的话可能会补充相关内容

  • Shadowsocks:使用 shadowsocks 服务器端软件和客户端软件即可实现科学上网。虽然不少人说它凉了,但其开发依然活跃,尤其是 shadowsocks-libev(C语言版)。
  • shadowsocksr:使用 shadowsocksr 服务器端软件和客户端软件即可实现科学上网。虽然它好久没有更新了,但是依然能用。
  • V2Ray:使用 V2ray 服务器端软件和客户端软件即可实现科学上网。新兴势力,开发活跃。
  • Vmess + WS + CDN:V2ray 中的一个方案,即“俗称”的“套cf”。由于用到的 CDN 通常是免费的 cloudflare,所以被网友戏称为“套cf”。它能让被墙 IPVPS 继续使用(SSSSR、V2ray 能用的前提是 IP 没被封)。
  • Vmess + WS + TLS + CDN:在上一个方案的基础上添加了 TLS,使其变成了常见的 HTTPS 流量,更隐蔽,更安全。
  • Vmess + WS + TLS + CDN + Web:在上一个方案的基础上添加了 Web 前端(或许应该叫前台?这里的称呼不严谨),通过反向代理让 V2ray 本身被隐藏起来,更更隐蔽
  • 通过已经可以科学上网的电脑实现科学上网:和已经可以科学上网的电脑位于同一局域网并开启它的允许来自局域网的连接(实质是让本地代理的监听地址从127.0.0.1 1080变成0.0.0.0 1080)即可

小结

须知,天下没有免费的午餐(就算有也很少 -_-)。上述的方法中,免费的那几种方法大多存在不安全、有流量限制、有速度限制、有广告、不稳定等问题。而付费的机场虽然体验极佳,但是价格昂贵,且通常只能 1~3 人使用。

而自己租用 VPS 则不然,相对安全、流量上限高(如 500G/月,你几乎不可能用完)、无广告、相对稳定,此外如果某个方法无效了换个方法即可,同时会学到更多知识,尤其是网络方面的知识。但是凡事皆有利弊,自己租用 VPS 的弊端在于你会遇到大量问题,花费大量时间。

至于如何选择,可以结合你的需求、兴趣、未来的研究方向综合考虑。我之所以从一开始就果断选择了自己租用 VPS 这条不归路(好吧,事实上最初我也用了将近一年的机场),是出于较大的科学上网需求、对科学上网的兴趣和所选择的研究方向——计算机科学与技术之网络安全。

因此,本文着重讲解,如何通过自己租用的 VPS 搭建代理服务器实现科学上网

自主搭建代理服务器实现科学上网大致流程

自主搭建代理服务器实现科学上网总体流程如下:

  1. 选择 VPS 提供商
  2. 租用 VPS
  3. VPS 上安装操作系统
  4. 连接到你的 VPS
  5. 配置公私钥登录
  6. 选择科学上网方案
  7. 配置你的服务器(VPS
  8. 配置你的客户端
  9. 测试

如前所述,本文重点在于方法-付费-VPS,即使用 VPS 自主搭建代理服务器实现科学上网。但是事实上,由于篇幅原因,本文侧重于讲解总体流程中的后面三个内容——配置你的服务器(VPS(方案相关)、配置你的客户端(方案相关) 、测试(方案无关,只讲一般思路)。因为它们才是重难点

选择 VPS 提供商

VPS 简介

VPS,全称 Virtual Private Sever,即虚拟专用服务器。它是一个在真实的服务器中虚拟出来的一个服务器环境,你可以在这个服务器上安装你喜欢的服务器端操作系统,然后做你想做的事,如搭建代理服务、搭建 Web 站点、搭建 VPN 服务等。维基百科中的介绍如下:

虚拟专用服务器(英语:Virtual private server,缩写为 VPS),是将一台服务器分割成多个虚拟专享服务器的服务。实现VPS的技术分为容器技术和虚拟机技术 。在容器或虚拟机中,每个VPS都可分配独立公网IP地址、独立操作系统、实现不同VPS间磁盘空间、内存、CPU资源、进程和系统配置的隔离,为用户和应用程序模拟出“独占”使用计算资源的体验。VPS可以像独立服务器一样,重装操作系统,安装程序,单独重启服务器。

——引用自虚拟专用服务器 - 维基百科,自由的百科全书

其中可安装的操作系统有很多,如 Ubuntu Server、CentOS、Windows Server等,笔者建议使用 CentOS,一个字——“稳”。当然,Ubuntu Server也不错,它有如下优势:

  • 使用体验和 Ubuntu(这里指 Bash)几乎完全一致。故适合用过 Ubuntu 的新手
  • 如果命令未找到,会提示你安装相应的软件包(CentOS可以直接使用yum provides <commandname>查找相应的命令的软件包)
  • 强大的自动补全功能。比 CentOS 强大。因为它甚至可以补全二级命令(如apt-get后的install命令),好像是因为它默认安装了一个叫bash_completion的软件包。

注意,几乎所有的 Linux 服务器版本都不会带图形界面,事实上,Linux 本身就不需要图形界面,请萌新尽早学会使用 Shell(如 Bash)

选择 VPS 提供商

由于提供上述 VPS 的商家很多,如 搬瓦工 vultr virmach hostdare cloudcone hosthatch anynode hostsolutions hostflyte justhost sentris gullo cheapnat GCP xenspec等等。如何选择成为一个比较复杂的问题。需要从价格、速度、稳定性、延迟、易用性等方面来考虑。

笔者使用的是搬瓦工(29.9$/年的那个套餐,不过现在已经没有,曾经还有一个 19.9$/年的套餐),但是近期(2019-06-03)搬瓦工的 IP 被封得有些厉害,故现在不是很推荐,当时选择它是因为它便宜且速度和稳定性尚可。

现在比较好用的 VPS 笔者也不清楚,建议使用搜索引擎搜索

2019-07-21 更新:笔者的搬瓦工 VPS IP 已于 2019-07-06 解封(被封了一个月左右)

租用 VPS

选择好了 VPS 提供商后,便可租用一个 VPS。租用时间可自行斟酌。如果未用过,网上也没有相关的测评,则建议租用时间短些(如 1 个月);如果网上好评如潮且不差钱,则直接 1 年起步即可

温馨提示:租用的 VPS 可以在某些渠道转卖

完成这一步后你需要对你的 VPS 有个大概的认识,主要包括如下几个方面的内容:

  • 你的 VPS 提供商是?这个问题的答案可以帮助你在遇到问题使用正确的关键字搜索。对于搬瓦工而言就是搬瓦工
  • 如何进入你的 VPS 的控制面板?这个问题最为重要,你必须知道 VPS 提供商为你提供了怎样的接口来访问和控制你的 VPS,以及如何使用这些接口。对于搬瓦工而言是 Bandwagon Host - Client Area中的KiwiVM Control Panel。其中有如下几个重要的功能(以搬瓦工为例,其它 VPS 提供商类似):
    • Main controls:在这里你可以查看你的服务器的概况。包括所在位置、公网 IPSSH端口、状态、内存和 SWAP 使用情况、磁盘使用情况、带宽使用情况、操作系统、主机名、PTR记录
    • Root - shell interactive:这个接口在你使用 SSH 连不上 VPS 时非常有用。它让你可以直接通过 Web 使用 Shell 对你的 VPS 进行控制
    • Install new OS:这个接口允许你重新安装操作系统。注意,重装操作系统,你之前操作系统上的所有更改过的数据将清空
    • Root password modification:搬瓦工直接提供了重新生成 root 密码的接口。如果你不知道 root 初始密码的话,你可以在这里生成后使用生成的新密码
  • 如何续费?这个问题在你完成一个租用周期依然想继续使用时显得格外重要。对于搬瓦工而言是 Bandwagon Host - Client Area - addfunds

VPS 上安装操作系统

租用了 VPS 后,有的商家可能直接给你安装了一个默认的操作系统,有的可能会让你自己部署。无论如何,你可能都会想要安装一个自己喜欢的操作系统。如上所述,笔者建议安装 CentOS 或者 Ubuntu Server。安装方法通常很简单,往往只需要点击一个按钮就可以了(如搬瓦工)

安装好你喜欢的操作系统后,你需要知道如下相关信息:

  • IP 地址
  • SSH 端口
  • root 密码(或者配置 SSH 公/私钥)

从而为下一步的连接做准备

连接到你的 VPS

在这一步中,你需要使用 SSH 工具连接到你的服务器。在 Windows 中,你需要安装一个 SSH 客户端,例如 PuTTY、Xshell、Mobaxterm 等(对于 Windows 10 较新版本,自带 OpenSSH 客户端,可在 Powershell 或 CMD 中直接使用,如ssh -p 22 wsxq2@192.168.56.11,不过使用体验远不如 PuTTY 等软件);而 MacOS 则不需要,其终端支持良好,默认 Shell 为 Bash,ssh 应该是默认安装了的,所以直接使用ssh -p <port> <username>@<server ip>即可,如ssh -p 22 wsxq2@192.168.56.11

笔者使用的是 PuTTY

(我超级喜欢的 PuTTY 竟然更新了?今天点进去一看,我的天,时隔将近两年,PuTTY 终于更新了,现在(2019-07-06)最新版是 2019-03-16 发布的 0.71 版本 :sob:

(2019-07-21 更新:PuTTY竟然又更新了?:scream: 当前最新版是 2019-07-20 发布的 0.72 版本)

安装好 PuTTY 后,你便可以连接到你的 VPS 了:在Host Name中填写你的服务器的 IP 地址,在Port处填写你的服务器的 SSH 服务使用的端口,在Connection type处选择SSH(默认使用的就是SSH,这里提一下是为了以防万一)

如果你的服务器的 IP 没被封、TCP 没被阻断的话,应该就能连上。

第一次连接会提示The authenticity of host...balabala...之类的东东,这是为了防止有人冒充你的服务器接受你的连接从而套取你的密码,但是这是低概率事件,所以输入yes即可。

之后便会要求你输入用户名和密码,通常用户名默认为root,密码应该能在你的 VPS 的控制面板处找到,如果找不到,你可以在控制面板的 shell 接口处(对于搬瓦工而言是KiwiVM Control Panel中的Root - shell interactive)直接修改你的 root 密码(在 shell 中使用passwd命令即可)

登录成功后,你就可以对你的服务器进行配置了。

配置公私钥登录

上传 SSH 客户端的公钥到服务器以方便以后登录(即使用公私钥认证而非用户密码认证,公私钥认证的优点在于不需要每次手动输入密码)。具体方法如下(以 Windows10 上的 PuTTY 客户端为例):

  1. 使用PuTTYgen工具生成公私钥对。具体步骤如下:
    1. 打开 PuTTYgen。按快捷键Win+S->输入puttygen->回车
    2. 生成公私钥对。点击 Generate->随意晃动鼠标以生成随机参数->生成完成
  2. 复制公钥到剪贴板。全选Public key for pasting into OpenSSH authorized_keys file下面的文本框中的内容,按Ctrl+C复制到剪贴板
  3. 保存私钥到安全的位置。点击 Save private key->点击确定(为了方便不设置 passphrase,passphrase 相当于一个用于保护私钥文件的密码,如果设置了的话,每次使用私钥文件时都会要求输入 passphrase,除非使用 Pageant 工具)->选定要保存到的目录(建议放到个人目录C:\Users\<username>\putty中,注意其中<username>要替换成你自己的用户名)->确定
  4. 上传公钥到 VPS。使用 PuTTY 以用户密码的登录方式登录你的 VPS。登录成功后,使用如下命令:
    1
    
    echo '<公钥>' >> ~/.ssh/authorized_keys
    

    其中<公钥>是你之前生成的公私钥对中的Public key,在 PuTTY 中可以使用Shift+Insert粘贴剪贴板的内容(Ctrl+Insert是复制)

  5. 配置 PuTTY。具体步骤如下:
    1. 打开 PuTTY。Win+S->输入putty->回车
    2. 设置主机和端口。在主界面输入Host NamePort
    3. 设置默认登录用户名。在 PuTTY 主界面点击左侧的Connection中的Data,在Login Details处的Auto-login username处输入root(通常是使用root登录 VPS
    4. 设置使用的私钥文件。点击左侧的Connection中的SSH中的Auth,在Authentication Parameters处点击Browse,选择你刚刚保存的私钥文件
    5. 设置字体和大小(可选)。PuTTY 默认的字体和字体大小过于丑陋,可以简单设置一下。点击Window中的ApprearanceFont setting处的ChangeFont处输入consolasSize选择14,点击OK
    6. 保存为一个会话。点击左侧的Session回到主界面,在Saved session处输入bwg(或者一个你喜欢的名字),然后点击右下侧的Save
  6. 使用公私钥登录。打开 PuTTY,双击Saved session中的bwg即可

选择科学上网方案

方法-付费-VPS-使用的方案处已经提到了现今比较流行的方案。从中选择一个即可。

如果 IP 没被封,笔者建议使用 Shadowsocks,因为其历史悠久(相对于 SSR 和 V2Ray),操作简单,文档丰富(V2Ray 文档也挺好);如果 IP 被封了,建议使用 Vmess + WS + CDN 的方案

2020-06-19更新:现在 shadowsocks 不那么靠谱了(个人体验,可能因人而异),推荐 v2ray Vmess(简单,比后面的都快),更推荐 trojan(TCP+TLS,比后面那个更快,不能套 CDN),最推荐 v2ray Vmess+WS+TLS+Web(可以套 CDN

选择的方案不同,配置服务器和客户端的步骤也不同。

配置你的服务器(VPS

根据你选择的方案参见后文相应的内容

配置你的客户端

根据你选择的方案参见后文相应的内容

对于大多有图形界面的客户端软件(如 SSR for Windows——shadowsocksr-csharp)而言,配置都相当简单,网上很容易搜到图文教程,本文会一笔带过。

本文着重讲解没有图形界面的客户端软件(如 SSR for Linux——shadowsocksr(Python版))

测试

测试是个非常重要的环境,很多人在失败之后一脸懵逼,只知道自己没成功,但不知道为什么没成功

由于测试(调试)自古以来是难点,因为导致出错的原因很多,让人不知从何下手。然而本文针对的就是这种难点。因此后文将大致介绍测试思路和测试工具

通用代理

温馨提示:从这一部分开始,本文就开始对具体的科学上网方案(参见方法-付费-VPS-使用的方案)作详细的讲解。由于内容庞杂,可能会不断扩充

如前文所述,起初 GFW 没有现在这么强大的时候,大家可以通过简单的通用代理服务器实现科学上网。这里的通用代理服务器指的是 HTTP 代理服务器和 SOCKS 代理服务器。其中 HTTP 代理服务器最为常用。

虽然通用代理对于现今的 GFW 已经没有作用,但其原理和相关协议(例如 socks5 )依然在使用,包括现在的 SSSSR、V2Ray,都和通用代理实现科学上网使用了几乎相同的原理。比如大家熟知的 SS 方案的服务器端便是相当于一个使用 SS 协议的代理(监听地址通常为<VPS ip> 8388),而其客户端则在本地主机上搭建了一个 SOCKS 代理服务器(监听地址通常为127.0.0.1 1080),通过这种双代理的方式实现科学上网

在了解通用代理之前,我们需要对代理有一些了解。因为代理这个概念是自主搭建代理服务器实现科学上网的核心

代理简介

代理本身是一个很宽泛的概念,维基百科对它的解释如下:

代理(英语:Proxy)也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。

——引用自代理服务器 - 维基百科,自由的百科全书

事实上,代理这一块的内容相当多,也相当复杂。就连代理的分类都比较复杂,相关的英文维基百科页面中将代理分为开放代理反向代理,其中开放代理又分为匿名代理透明代理(参见 Proxy server - Wikipedia(英文版的代理服务器页面))。然而并不知道其是否正确。因此,本文只涉及科学上网过程中可能用到的代理相关的知识。

代理的一般原理:客户端(如你的浏览器)<->代理服务器(如你的 VPS)<->目标站点(如 www.google.com )

其中客户端代理服务器之间可以使用各种代理协议,例如 HTTPSOCKSSSSSR、Vmess(V2Ray) 等等。其中 HTTPSOCKS 是早期使用的代理协议,现今因为其极易被 GFW 侦测和识别,所以已经不会用在客户端代理服务器之间,而是用于本地代理(如 SSSSR、V2Ray);相应地,SSSSR、Vmess 是现在主流的用于穿墙的代理协议。

2019-08-04 更新:这里将 SS/SSR 理解为独立的新的协议是有问题的,因为维基百科中说它们基于 SOCKS5 协议,或者说就协议而言用的就是 socks5 协议,只是在发送数据前进行了加密和混淆而已(待引证或分析 SS 等软件的源码以证明)。文中的其它部分也存在这个问题

常见的代理方法如下(按出现时间先后顺序排列,但没有严格依据):

代理方法 说明
No Proxy 最初是没有代理的,所有应用都是直连到目的站点
HTTP 后来为了访问直连访问不了的网站,出现了 HTTP 代理
PAC 再后来为了提高代理的灵活性,实现只代理该代理的,不代理不必要代理的 Web 站点这一目标,出现了 PAC (代理自动配置)。它实质上是一个 JS 脚本
WPAD 更后来,为了配置上的方便,即懒得在每个客户端主机上设置 PAC 代理,于是出现了 WPAD (网络代理自动发现协议)
Use System settings 更更后来,为了避免对每一个 Web 客户端进行代理配置,于是出现了系统代理配置(全局),一次配置,多个应用程序使用,方便、快捷。系统代理设置通常支持 HTTP 代理和 PAC 这两种(可能还支持 WPAD
SOCKS 更更更后来,为了能够高效代理非 Web 应用(如 SSH),于是发明了 SOCKS 协议。需要注意的是,HTTP 代理也支持非 Web 应用(使用 CONNECT),但是不够高效
HTTPS(SSL/TLS) 更更更更后来,为了能够实现更加安全的代理,出现了基于传输层安全(TLS)之上的 HTTP 代理——HTTPS
其它 更更更更更后来,为了对付日渐强大的 GFW,实现科学上网,出现以 SS 为首的各种代理协议,如 SSSSR、Vmess 等

后文将讲解上述代理方法中的 HTTPPACWPADSOCKS、其它,其中着重讲解 HTTPSOCKS。对于其它代理协议(如 SSSSR、Vmess),将在更后面详细讲解,但着重于应用而非协议细节

版权相关:本部分后面的部分内容(HTTP 代理,SOCKS 代理)修改自 有关几种网络代理协议的探讨 - 图文 - 百度文库。若侵权请联系wsxq2@qq.com删除

HTTP 代理

HTTP 本身是一个用于 Web 的协议,但是其具有代理功能。为了使用它的代理功能,我们需要对 HTTP 协议有个大概的了解

HTTP 协议

HTTP 协议是一个属于应用层(参见 OSI模型 - 维基百科,自由的百科全书)的协议。它于1990年提出,经过十几年的使用与发 展,得到不断地完善和扩展。目前在 WWW 中主要使用的是 HTTP/1.1 版。

HTTP 协议中.主要有 GET、POST、CONNECT 和 HEAD 等请求方法。为了把服务器的请求信息传递给客户.HTTP 定义了以下四部分工作过程:

  1. 客户机建立起与服务器的连接。建立一次连接的过程是这样的.客户机打开一个套接字(Socket)并把它约束在一个端口上。打开一个套接字就是建立一个虚拟文件,当向文件上写完数据后,数据在网络上传输。在这之前,HTTP 服务器已在运行,监听某个端口(通常是 80 )等待连接的建立。它们通过 TCP 三次握手进行连接
  2. 客户机向服务器发出请求,指出要检索的文档。连接建立以后,客户机就可以发出请求将请求数据发送到服务器指定的端口。例如:GET <URI> HTTP/1.1。其中GET是方法。用于从服务器请求一个由<URI>标识的资源对象。如果对象是文档或文件,GET 将请求其内容,如果对象是程序或脚本.GET 将请求程序的运行结果或脚本的输出。
  3. 服务器发出响应,包括状态码和文档的正文。当服务器接收到浏览器发出的请求时,搜索客户所需资源并响应。
  4. 客户机或者服务器任一方断开连接。

有关 HTTP 协议的更多信息,请参见 超文本传输协议 - 维基百科,自由的百科全书

基于 GET、POST 方法的代理

如前所述,HTTP 协议具有代理功能。其中最常用的便是基于 GET 和 POST 方法的代理。它们主要用于代理 HTTP 协议,结合缓存可以大大提高效率

HTTP 协议中规定了与代理相关的三个实体:

  1. 客户机(Client):一个用于发送 HTTP 请求数据的应用程序。例如浏览器
  2. 服务器(Server):一个接受 HTTP 请求数据并返回相应响应数据的应用程序。例如 Apache、Nginx 等
  3. 代理(Proxy):一个中间程序,它可以充当一个服务器(接受客户机的请求).也可以充当一个客户机(向服务器发起请求)。

当客户端是用通常的代理模式时(即使用 GET 或者 POST 方法发出请求),在客户端与代理服务器建立连接后,代理服务器将收到请求命令。这时代理服务器应该截取主机名部分进行域名解析,并同该主机建立连接,将去掉主机名部分的请求命令转发给它,等待它做出响应,然后将得到的响应转发给客户端,最后断开连接。其工作下图所示:

基于GET-POST方法的HTTP代理原理.png

注:

  • 1.客户连接代理服务器,并发出客户请求;
  • 2.在本地缓存中无此资源时。连接到Internet;
    1. 从Internet上获得所请求的资源;
  • 4.将客户所请求的资源发送给客户;
  • 2’.代理服务系统检索缓存数据库;
  • 3’.如果客户请求的资源在数据库中.则直接将请求的资源发给代理服务器。

由于 GET 和 POST 方法是工作在 HTTP 本层内,对代理服务器而言,接受或发送的数据都是可以理解的,这样它就可以将服务器应答的网页信息存储起来,当再有相同请求的时候,代理就可以快速的将客户端所需内容发送给客户端了。这个方法极大的提高了代理服务器的效率。

基于 CONNECT 方法的代理

HTTP 代理中,还有一种隧道代理方式,那就是使用 CONNECT 方法来请求并建立隧道。CONNECT 方法请求代理服务器为客户端和目标服务器建立一个连接通道。这种方法可以用来代理任意应用层协议,如 SSH 等。类似于 SOCKS 协议

在 CONNECT 方法中,请求命令行的请求 URI 部分总是指明请求连接的目的主机名和端口号,由冒号分隔。例如:

1
2
CONNECT example.com:80 HTTP/1.1
Host:example.com:80

在代理服务器作出成功的响应后,由客户端到服务器的隧道就被建立起来了。这种代理方式实际上是工作在应用层之下,因此代理服务器并不能对客户端与服务器发送来的数据进行理解.而只是简单的转发,所以基于 CONNECT 方法的代理方法不能进行缓存,但是它能够进行级联,也就是可以连接到下一个代理服务器进行中转。

VPS 上搭建 HTTP 代理

使用 apache、Nginx 均可,不过如果只是为了实现 HTTP 代理,它们显得过于庞大了。作为替代,可以选择使用 tinyproxy。tinyproxy 是一个小巧且高效的 HTTP/HTTPS 代理服务器。

但是由于这种方法已经过时,故本文不会细讲

通过 HTTP 代理进行 DNS 查询

HTTP 代理 DNS 的解析必然是通过代理的:

对于 HTTP/HTTPS 类型的代理服务器而言,请求的域名会作为 HTTP 协议的一部分直接发往代理服务器,不会在本地进行任何解析操作。也就是说,域名的解析与连接目标服务器,是代理服务器的职责。浏览器本身甚至无须知道最终服务器的 IP 地址。据我所知,此行为无法通过浏览器选项等更改。

也就是说,理论上使用 HTTP/HTTPS 类型的代理服务器时,本地的 DNS 解析、缓存、 hosts 文件等都不使用,与本地设置的 DNS 服务器地址无关。DNS 解析完全在代理服务器上进行。

——引用自请问在设置http/https代理后DNS的解析还是通过proxy吗?? · Issue #963 · FelisCatus/SwitchyOmega

所以无需这方面花太多时间。与之形成对比的是后文阐述的 SOCKS 代理,其对于 DNS 查询的处理就比较复杂

在本地代理中的应用

这里的本地代理指的是 SS 等方案中应用程序(如浏览器)和 SS 客户端程序(监听端口通常为 1080 )之间的连接。需要注意的是,在本地代理中,客户端应用程序通常是 Web 客户端(包括但不限于浏览器、浏览器插件、curl、wget、git),服务器应用程序通常是 SSSSR 或 V2Ray 客户端程序(如 SS 的 shadowsocks-libev 中的 ss-localSSR 中的 shadowsocksr-csharp 等等)。

HTTP 代理出现得在代理中出现最早(待引证),所以应用最为广泛。因此几乎所有支持代理的客户端应用程序都支持 HTTP 代理。如下表所示:

客户端应用程序 测试平台 是否支持 HTTP 代理 备注
Firefox Windows 10
Firefox 的 FoxyProxy 插件 Windows 10
curl Linux
Chrome 的 SwitchyOmega 插件 Windows 10
Kali 系统代理设置 Kali Linux 2.0
git Linux
IE(系统代理设置) Windows 10 注意,Windows 10 系统代理设置实质上和 IE 的代理设置是一样的
wget Linux
Chrome Windows 10 Chrome 使用系统代理设置(即 IE 代理设置,见前面相应的行)

需要注意的是,Windows 10 的设置中的手动代理设置使用的是 HTTP 代理,所以对于只支持 SOCKS 代理的客户端(如 SSH-D参数),在这里设置是行不通的

此外,对于服务器应用程序,通过查阅相关文献,得出了如下结论:

对于 SS 等工具而言,原始的服务器应用程序(实际上是 SS 等工具的客户端)不支持 HTTP 代理,只支持 socks5 代理;而 Windows 上的通常都支持 HTTP 代理,且都通常是使用 privoxy 工具转换的,其它衍生的带图形化界面的客户端可能支持 HTTP 代理

如下表所示:

服务器应用程序 测试平台 是否支持 HTTP 代理 备注
shadowsocksr-csharp Windows 10 它使用了 privoxy 工具将 SOCKS 代理转换为 HTTP 代理
shadowsocks-windows Windows 10 同样使用了 privoxy 工具
shadowsocks-qt5 未测试 参见 使用手册 · shadowsocks/shadowsocks-qt5 Wiki
shadowsocks-libev 中的 ss-local Linux
shadowsocksr-python 中的 local.py Linux

由于大多客户端应用程序默认的代理均指 HTTP 代理,所以其配置相当简单。下面将以 Windows10 的设置为例,简单说明一下

Windows 10 系统代理设置

前提:你在127.0.0.1 1080处配置了个 HTTP 代理服务器(如使用后文所述的 shadowsocks-csharp 即可,不过这样得到的不是纯 HTTP 代理,它还支持 SOCKS

  1. 打开设置。使用快捷键Win+I即可
  2. 找到代理相关的设置。点击右上角的网络和 Internet->点击左下角的代理
  3. 关闭自动代理配置并开启手动代理配置。在自动代理配置部分下将自动检测设置(对应 WPAD)和使用配置脚本(对应 PAC)关掉,将手动代理配置下的使用代理服务器开启
  4. 输入IP端口。在IP输入框中输入127.0.0.1,在端口输入框中输入1080
  5. 点击下方的保存。滑动到最下方,点击保存

完成!

现在让我们看个有趣的事情。打开 IE 中的代理设置,如下图所示:

系统设置中的手动代理设置为127.0.0.1时IE中代理设置的变化.png

由此可知 Windows 10 系统设置中的代理设置默认设置为 HTTP 代理(访问 HTTP,Secure(HTTPS),FTP 站点时均使用 HTTP 代理,而 Socks 为空),且会和 IE 设置同步。即 Windows 10 的系统设置中的代理设置是 IE 中代理设置的上层,它用过调用 IE 的代理设置来完成代理设置,且默认使用 HTTP 代理

让 UWP 应用走系统设置中的代理

有的 UWP 应用自身支持设置代理,例如 Telegram UWP 版。但大多数应用不支持在应用中设置代理,如微软的邮件和日历。对于不支持自己设置代理的 UWP 应用,可以使用全局代理(即系统设置中的代理)

  • 首先,UWP是可以使用全局代理的。也就是说,必须从系统设置里面设置代理才会有效。
  • 第二,系统屏蔽UWP的loopback是出于安全性考虑。虽然这可以通过win32提供的api禁止,但UWP应用不能更改这项屏蔽,微软也没有考虑将loopback作为权限开放。
  • 第三,就算解除了loopback的系统限制,UWP可以使用的loopback也是有限的。即无论是tcp还是udp,win32或uwp应用都无法连接到UWP应用上打开的服务器(绑定的端口)。对于udp,则UWP应用向loopback发送的任何消息都会被系统屏蔽。当然还是有方法解除这一限制的。

——引用自 为什么以 Windows 应用商店为代表的 UWP 不能使用代理? - 知乎中 Afanyiyu 的回答

要想使用全局代理,需要将对应的 UWP 应用添加到屏蔽 loopback 的排除列表(因为我们设置的是本地代理,监听地址是环回地址)。一个简单的方法是使用 Fiddler。具体步骤如下:

  1. 打开 Fiddler。按Win+S->输入fiddler->回车
  2. 打开 WinConfig。点击 Fiddler 中左上角的WinConfig,并允许管理员权限申请
  3. 选择正确的 UWP 应用。在弹出的AppContainer Loopback Exemption Utility窗口中选择要使用全局代理的 UWP 应用

    这里所谓的“正确”非常重要。比如对于邮件和日历这个 UWP 应用,实际需要勾选以下三个应用:

    • 邮件和日历
    • microsoft.windows.authhost.a_8wekyb3d8bbwe
    • email and accounts

    如何知道哪些是“正确的”?答案是试。想个比较快的方法很容易将它试出来

  4. 保存。点击Save Changes

详情参阅 如何为 Windows 10 UWP 应用设置代理 - 知乎

Windows 真·系统全局代理(透明代理)

由于我们科学上网的主要目的在于访问国外的 Web 网站,即客户端是使用 HTTP 协议的浏览器。众所周知,HTTP 协议是基于 TCP 的,上述方法对于基于 TCP 的 Web 浏览器而言自然没有问题。

但是在玩游戏时,可能会大量用到 UDP 协议(就算不玩游戏,DNS 也是基于 UDP 的,虽然 DNS 有很多其它的解决办法)。

由前所述,HTTP 基于 TCP 协议,虽然有 CONNECT 方法可以用于代理非 Web 应用,但是它支持代理使用 UDP 协议的流量吗?

此外有的游戏(或应用)可能不会理会 Windows 系统设置中的代理设置。那么问题来了,如何让所有应用强制走代理?甚至包括使用 UDP 协议的应用?

答案是劫持流量

进一步的分析日后进行(又挖了一个大坑)

PAC

简介

代理自动配置(英语:Proxy auto-config,简称PAC)是一种网页浏览器技术,用于定义浏览器该如何自动选择适当的代理服务器来访问一个网址。

一个PAC文件包含一个JavaScript形式的函数“FindProxyForURL(url, host)”。这个函数返回一个包含一个或多个访问规则的字符串。用户代理根据这些规则适用一个特定的代理器或者直接访问。当一个代理服务器无法响应的时候,多个访问规则提供了其他的后备访问方法。浏览器在访问其他页面以前,首先访问这个PAC文件。PAC文件中的URL可能是手工配置的,也可能是是通过网页的网络代理自动发现协议(WPAD)自动配置的。

——引用自 代理自动配置 - 维基百科,自由的百科全书

PAC 实现了自动代理,即只代理需要代理的,不代理不需要代理的,而且还可以提供多个代理服务器,在某个失效时自动切换至另一个。其核心是 PAC 脚本,它实质上是一个 JS 文件(也被称为 PAC 文件)。该文件只有FindProxyForURL函数是必需的。详细内容请点击上面给出的维基百科的链接以查看。

一个最简单的 PAC 文件长这样:

1
2
3
4
function FindProxyForURL(url, host)
{
	return "SOCKS5 127.0.0.1:1088; DIRECT";
}

代表的含义也非常明显,即优先使用127.0.0.1 1080这个 SOCKS 代理进行访问,如果访问失败再通过直连访问。

对于 SOCKS 代理而言,使用 PAC 有两个好处,第一个好处是可以让手动代理不支持 socks5 的浏览器支持 socks5 代理(如 Windows 下的 Chrome,它使用系统的代理设置,而系统的代理设置只支持 socks4);第二个好处在于可以避免 DNS 污染,因为在 PAC 文件中像上面那样写的话,DNS 查询必然会通过 socks5 代理服务器进行(参见 关于 SOCKS 代理的远端 DNS 解析 | 边际效应 - 杨文博

其中返回的值除了SOCKS5 127.0.0.1:1088DIRECT之外,还可以为如下形式:

最初:

  • DIRECT

    直接连接

  • PROXY host:port

    指定 HTTP 代理服务器

  • SOCKS host:port

    指定 SOCKS 代理服务器

后来新增:

  • HTTP host:port

    明确指定使用 HTTP 代理服务器

  • HTTPS host:port

    明确指定使用 HTTPS 代理服务器(然而我到现在也没弄懂 HTTPS 代理服务器是啥)

  • SOCKS4 host:port

    明确指定使用 SOCKS 代理服务器,且使用版本 4 的协议(具体是 socks4 还是 socks4a 依然不清楚)

  • SOCKS5 host:port

    明确指定使用 SOCKS 代理服务器,且使用版本 5 的协议(即 socks5)

PAC 脚本通常保存为 proxy.pac,且其 MIME 类型通常设置为application/x-ns-proxy-autoconfig(在 Apache 中设置 MIME 类型超级简单,只需要在其主配置文件/etc/httpd/conf/httpd.conf中添加AddType application/x-ns-proxy-autoconfig .pac即可,也可直接修改/etc/mime.types文件)

需要注意的是 PAC 脚本实现代理只适用于浏览器(毕竟是 JS 脚本嘛),不能用于其它应用

关于 PAC 的更多信息请参见 breakwa11/gfw_whitelist: gfw_whitelistProxy servers and tunneling - HTTP | MDN 中的 Proxy Auto-Configuration (PAC) 部分

应用举例

Kali Linux 通过系统设置配置 PAC 实现自动科学上网
  • 前提:有个 SS/SSR 账号,且已经配置好客户端(即已在127.0.0.1 1080处搭建了 socks5 代理)。如何在 VPS 上搭建 SS/SSR 服务器及配置相应的客户端请参见后文
  • OS:Kali 2.0

此方法主要使用了genpac(GENerate PAC file)生成 PAC 文件,并将系统设置中的网络代理方式改为自动,将其Configuration URL指向相应的 PAC 文件位置。具体过程如下:

  1. 安装genpac
    1
    2
    3
    4
    
    #安装
    pip install genpac
    #更新
    pip install --upgrade genpac
    
  2. 生成PAC文件:
    1
    2
    3
    4
    
    mkdir ~/.pac
    cd ~/.pac
    touch user-rules.txt #可在此文件中添加用户自定义规则,此处省略
    genpac --pac-proxy "SOCKS5 127.0.0.1:1080" --output="ProxyAutoConfig.pac" --user-rule-from="user-rules.txt"
    
  3. 设置系统自动代理:设置->网络->网络代理,方式改为自动Configuration URL改为file:///root/.pac/ProxyAutoConfig.pac(注意我用的是root用户,如果非root用户请将/root改为/home/<your username>
  4. 测试:打开浏览器,输入网址www.google.com看是否访问成功

2019-07-03 更新:该方法存在的问题是如果你的 PAC 文件失效了,可能需要重新下载 PAC 文件,即重新执行第 2 步中的genpac步骤。

Windows 上使用 PAC 实现科学上网——情形一
  • 前提:有个 SS/SSR 账号,且已经配置好 Windows 客户端(shadowsocks-windows、shadowsocksr-csharp)。如何在 VPS 上搭建 SS/SSR 服务器及配置相应的客户端请参见后文
  • OS:Windows 10

对于 SS 的 Windows 客户端 shadowsocks-windows,它直接提供了 PAC 支持,不需要自己生成 PAC 文件。具体获取方法如下:

右键任务栏右边的小飞机图标->鼠标移至PAC->点击Copy Local PAC URL

然后在可以设置 PAC 的地方设置即可。如 Windows 10 系统设置中的代理设置处、Chrome 浏览器的 SwitchyOmega 插件的新建 PAC 情景模式处、Firefox 浏览器的设置中的网络设置处、Firefox 浏览器的 FoxyProxy 插件的 Add Proxy 处等。

SSR 类似。至于 V2Ray,其本身并不支持 PAC(事实上,SS/SSR 本身也不支持 PAC ,只是其部分带 GUI 的客户端支持,尤其是 Windows),所以需要自己写 PAC 文件或者根据已有的 PAC 文件进行修改。在这里就不详述了

Windows 上使用 PAC 实现科学上网——情形二
  • 前提:有个国外的 VPS,该 VPS 可直接访问谷歌,你的笔记本可通过 SSH 连上该 VPS,且使用了 SSH-D参数(参见后文SSH-D参数)。具体的命令如下:
    1
    
    ssh -N -D 1088 -p26635 root@wsxq21.55555.io
    
  • OS:Windows 10

SSH-D参数只支持 socks5 代理,且没有直接的 PAC 支持,所以需要我们自己写 PAC 脚本。之所以会提到这个情形,是因为 Windows 系统代理设置不支持 socks5,而通过 PAC 脚本,即可让 Windows 上的浏览器支持 socks5

现在我们写个简单的脚本:

1
2
3
4
function FindProxyForURL(url, host)
{
	return "SOCKS5 127.0.0.1:1088; DIRECT";
}

将它保存到C:\Users\wsxq2\Desktop\proxy.pac。然后在系统代理设置中的自动代理配置下的使用配置脚本处填写file:///C:/Users/wsxq2/Desktop/proxy.pac。理论上是可以的,然而事实上去不行。究其原因,在于:

This issue occurs because Internet Explorer and Edge on Windows 10-based computers use the WinHttp proxy service to retrieve proxy server information. The WinHttp Proxy service does not support using the ftp:// or file:// protocol for a PAC file.

——引用自 Windows 10 does not read a PAC file referenced by a file protocol

有关 Windows 的代理设置详细信息,可参见 Understanding Web Proxy Configuration – IEInternals

虽然在 Windows 10 下, IE、Edge 和 Chrome(Chrome 使用系统的代理设置,即 IE 的代理设置)这几个浏览器不支持本地文件的 PAC 代理,但是有个浏览器却支持,它就是 Firefox。所以在 Firefox 的设置网络设置处,将自动代理配置URL 设置为file:///C:/Users/wsxq2/Desktop/proxy.pac是可行的。

值得注意的是 Chrome 浏览器的 SwitchyOmega 插件也不支持file://PAC 文件地址,但是它可以直接录入 PAC 脚本,更为方便可靠

另外 Firefox 浏览器的插件 FoxyProxy 并不支持 PAC, WAPD, System Settins。当选择上述之一时会出现如下错误提示:

1
2
Not supported
Due to several Firefox bugs, PAC, WPAD, and System Settings are not yet supported.

WPAD

先放个维基百科的链接镇一下场面,回头有空再填这个坑:网络代理自动发现协议 - 维基百科,自由的百科全书

SOCKS 代理

Socks 代理协议是从 1990 年开始发展的,此后,就一直作为 Internet RFC 中的开放标准。目前,主要有两个版本的 Socks 协议,版本4和版本5(中间还有个 socks4a,但似乎应用不广,故不做阐述)。Socks版本4被简写为“Socks4”,Socks版本5被简写为“Socks5”。与 HTTP 协议不同,Socks 协议实际上是一个纯代理协议。Socks 协议从概念上来讲是介于应用层和传输层之间的“中介层(shim—layer)”,因而实际上是一个“全能”的代理协议,可以代理各种应用层协议,而不仅仅局限于代理 HTTP 协议。

Socks 协议模型

Socks4 协议执行三个功能:连接请求、代理链路的建立和应用数据中转。Socks5协议增加了鉴别功能。其控制流程图如下所示:

SOCKS协议控制流程图.png

上图显示了 Socks5 控制流模型,虚线框中的部分代表 Socks4 的功能。

当应用客户在需请求外部网络的应用服务器服务时,首先与 Socks 服务器建立连接。它向 Socks 服务器发出连接请求及相关的信息,如所支持的鉴别方法列表。Socks 服务器接到消息后,检查安全配置策略,返回服务器选择的安全鉴别方法。Socks 客户再对服务器所作选择进行验证.Socks 客户及服务器分别根据选择的鉴别方法进行处理。Socks 客户向 Socks 服务器发送代理请求。Socks 服务器处理客户的请求,设置代理链路,建立与应用服务器的连接,并向 Socks 客户发送设置状态。而后。Socks 服务器在 Socks 客户与应用服务器之间中转数据。

更多相关信息请参见 SOCKS - 维基百科,自由的百科全书

Socks 协议的优缺点

优点:

  1. Socks 协议是一个纯代理协议,因此比 HTTP 更高效。它可以进行级联。
  2. Socks4 协议由于较为简单.只能简单的按源地址进行访问控制;而 Socks5 协议可以有多种访问控制机制,还可以进行域名地址解析,更进一步减少了客户端的工作量。

缺点:

  1. Socks协议不是应用层代理协议.它并不能理解所代理的网络协议内容,因此不能通过进行本地缓存来提高访问速度。

VPS 上搭建 SOCKS 代理

使用 SS5 即可

但是由于这种方法已经过时,故本文不会细讲

通过 SOCKS 代理进行 DNS 查询

使用 socks4a 新增的 HOSTNAME 字段

该方法也叫做 “远程 DNS 解析”。使用最多

socks4a 是 socks4 协议的简单扩展,允许客户端对无法解析的目的主机,进行自行规定。

客户端对 DSTIP 的头三个字节设定为 NULL,最后一个字节为非零;对应的IP地址就是 0.0.0.x,其中 x 是非零,这当然不可能是目的主机的地址,这样即使客户端可以解析域名,对此也不会发生冲突。USERID 以紧跟的 NULL 字节作结尾,客户端必须发送目的主机的域名,并以另一个 NULL 字节作结尾。CONNECT 和 BIND 请求的时候,都要按照这种格式(以字节为单位):

VN CD DSTPORT DSTIP 0.0.0.x USERID NULL HOSTNAME NULL
1 1 2 4 variable 1 variable 1

使用 socks4a 协议的服务器必须检查请求包里的 DSTIP 字段,如果表示地址 0.0.0.x,x是非零结尾,那么服务器就得读取客户端所发包中的域名字段,然后服务器就得解析这个域名,可以的话,对目的主机进行连接。

——引用自 SOCKS # socks4a - 维基百科,自由的百科全书

使用 socks5 新增的 UDP 转发

DNS 查询通常通过 UDP/53 进行(有时会用到 TCP),而 SOCKS 客户端通常是基于 TCP 的。所以这里通过 SOCKS 代理进行 DNS 查询也被称为 “UDP Over TCP

SOCKS5请求格式(以字节为单位):

VER CMD RSV ATYP DST.ADDR DST.PORT
1 1 0x00 1 动态 2
  • VER 是 SOCKS 版本,这里应该是0x05
  • CMDSOCKS 的命令码
  • 0x01表示 CONNECT 请求
  • 0x02表示 BIND 请求
  • 0x03表示 UDP 转发
  • RSV 0x00,保留
  • ATYP DST.ADDR类型
    • 0x01 IPv4地址,DST.ADDR 部分4字节长度
    • 0x03 域名,DST.ADDR 部分第一个字节为域名长度,DST.ADDR 剩余的内容为域名,没有\0结尾。
    • 0x04 IPv6地址,16个字节长度。
  • DST.ADDR 目的地址
  • DST.PORT 网络字节序表示的目的端口

——引用自 SOCKS # SOCKS5 - 维基百科,自由的百科全书

通过使用 UDP 转发,你就可以在本机设置一个国外的 DNS 服务器,每次向它发起 DNS 查询时都会通过代理进行(理论上,个人理解,待验证)

关于 shadowsocks-libev 的 UDP 转发是如何实现的可参考 ss-libev 源码解析udp篇 (1) - 技术无界 - CSDN博客

结合其它工具

对于这部分的内容,原理尚待分析

使用 dns2socks(Github 上也有其项目地址https://github.com/qiuzi/dns2socks)或 overture

此外,shadowsocks-libev 中的 ss-tunnel 也能实现该功能。和 dns2socks 相比,ss-tunnel 走 TCP(即 socks5),而 dns2socks 走 UDP

具体步骤就不详述了

转换 SOCKS 代理为 HTTP 代理

2019-07-04 更新:相关的工具有很多,例如 Polipo、privoxy等。这里使用的工具是 Polipo。需要注意的是 Polipo 最后一次更新是在 2014-05-15(参见 Polipo - Wikipedia),因此更建议使用 privoxy(最后一次更新是在 2016-08-27)

如前所述,通用代理只有两种:HTTP 代理(使用 HTTP 协议)和 SOCKS 代理(使用 socks4/socks4a/socks5 协议)。最常见且最普及的是前者,有的应用不支持后者。所以为了让那些不支持 SOCKS 代理的应用程序使用代理,需要将 SOCKS 转换为 HTTP 代理。

Polipo可以用来将SOCKS的代理转换为HTTP的代理,从而使那些只支持HTTP代理的软件(如wget,部分浏览器,部分操作系统(如 Windows 就只支持 http 代理和 socks4 代理,这是我通过抓包分析发现的))也可以科学上网

以下操作是在 Kali 上进行的,其它基于 Debian 的 Linux 类似:

  1. 安装polipo:
    1
    
    apt install polipo
    
  2. 修改/etc/polipo/config文件为如下内容:
    1
    2
    3
    4
    5
    6
    7
    
    logSyslog = true
    logFile = /var/log/polipo/polipo.log
       
    socksParentProxy = "127.0.0.1:1080"
    socksProxyType = socks5
    proxyAddress = "0.0.0.0"
    proxyPort = 8123
    
  3. 重启polipo(安装后它会自动启动,故这里说重启):
    1
    
    systemctl restart polipo
    
  4. 验证 polipo 是否正常工作:
    1
    2
    
    export http_proxy=http://127.0.0.1:8123/
    curl www.google.com
    

    如果正常,就会返回抓取到的 Google 网页内容。可通过man polipo查看其帮助文档。

在本地代理中的应用

这里的本地代理指的是 SS 等方案中应用程序(如浏览器)和 SS 客户端程序(监听端口通常为 1080 )之间的连接。需要注意的是,在本地代理中,客户端应用程序通常是 Web 客户端(包括但不限于浏览器、浏览器插件、curl、wget、git),服务器应用程序通常是 SSSSR 或 V2Ray 客户端程序(如 SS 的 shadowsocks-libev 中的 ss-localSSR 中的 shadowsocksr-csharp 等等)。

对于客户端应用程序,通过艰辛的抓包实验(使用工具 WireShark),得出常见客户端应用程序对于 SOCKS 代理的支持度如下(按对 SOCKS 代理的支持度排序):

客户端应用程序 测试平台 支持的 SOCKS 代理 备注
Firefox Windows 10 socks4/socks4a/socks5 手动代理配置中,其 SOCKS v4 选项既支持 socks4,又支持 socks4a
Firefox 的 FoxyProxy 插件 Windows 10 socks4/socks4a/socks5 Proxy Type中的 SOCKS4 同时既支持 socks4,又支持 socks4a
curl Linux socks4/socks4a/socks5 curl 是一个 Linux 下的命令行工具
Chrome 的 SwitchyOmega 插件 Windows 10 socks4/socks5 不支持 socks4a
Kali 系统代理设置 Kali Linux 2.0 socks5 未测试是否支持 socks4/socks4a
git Linux socks5
IE(系统代理设置) Windows 10 socks4 不支持 socks4a/socks5。注意,Windows 10 系统代理设置实质上和 IE 的代理设置是一样的
Chrome Windows 10 不支持 Chrome 使用系统代理设置(即 IE 代理设置,见上一行)
wget Linux 不支持 wget 是一个 Linux 下的命令行工具

由于测试内容过多,难免有疏忽之处,如有错误,还请指正。

需要注意的是,Windows 10 的设置中的手动代理设置使用的是 HTTP 代理,所以对于只支持 SOCKS 代理的客户端(如 SSH-D参数),在这里设置是行不通的

此外,对于服务器应用程序,通过查阅相关文献,得出了如下结论:

Windows上的服务器应用程序(即 SS/SSR/V2Ray 客户端程序)通常实现了全能代理(即 http + socks4 + socks4a + socks5),而在 Linux 中的命令行工具(如 shadowsocks-libev 中的 ss-local)中则通常只实现了 socks5 代理

服务器应用程序 测试平台 支持的 SOCKS 代理 备注
shadowsocksr-csharp Windows 10 socks4/socks4a/socks5
shadowsocks-windows Windows 10 socks5 socks4/socks4a未测试
shadowsocks-libev 中的 ss-local Linux socks5 socks4/socks4a未测试
shadowsocksr-python 中的 local.py Linux socks5 socks4/socks4a未测试

下面将根据上文的结论对经典的使用场景进行演示。需要注意的是,你需要一个能连上的 SOCKS 代理服务器,如果你按照后文所述的那样在你的服务器(VPS)上配置了 shadowsocksr-python,在你的客户端(PC)上配置了 shadowsocks-csharp(for Windows)或 shadowsocksr-python(for Linux),那么你的客户端自己(即 IP 地址127.0.0.1,端口1080)就是一个代理服务器。而且如上所述,它至少支持 socks5 代理。

Firefox 浏览器中的代理设置

本部分的目标在于让 Firefox 浏览器浏览所有网页时都走代理。只需在 Firefox 浏览器中设置手动代理即可。

  1. 找到 Firefox 浏览器中的手动代理设置的位置:点击右上角的菜单,选择Preferences,选择General,滑到最下面,选择Network Proxy标签下的Settings,选择Manual proxy configuration
  2. 配置:找到SOCKS Host一栏,填入127.0.0.11080,在下面选择SOCKS v5,其它栏留空(如HTTP Proxy)。并在之后的No Proxy for中填入不需要代理的网址或 IP 地址或网段(例如 127.0.0.1、192.168.0.0/16等)。

    2019-07-04 更新:记得勾选下方的Proxy DNS when using SOCKS v5以防止 GFWDNS 污染。事实上,这里的Proxy DNS when using SOCKS v5设置和 Firefox 中的 中的`network.proxy.socks_remote_dns`设置是一样的。此外,对**连接**页面中的**手动代理配置**中的内容说明如下:

    • HTTP ProxyHTTP 代理服务器地址。须知,使用前面的方法在127.0.0.1 1080处搭建的代理服务器是 SOCKS 代理服务器(不是 HTTP 代理服务器),且使用的是 socks5 协议(不是 socks4/socks4a 协议)。所以在这里填写127.0.0.1 1080将无法访问(即必须留空)
    • SSL Proxy:访问 HTTPS 站点时使用的代理服务器地址,其实就是 HTTP 代理服务器地址。留空原因同上
    • FTP Proxy:访问 FTP 站点时使用的代理服务器地址,其实就是 HTTP 代理服务器地址(不过需要注意的是 FTP 代理是存在的,例如使用工具ftp.proxy)。留空原因同上
    • SOCKS Host:访问任意站点时使用的代理服务器地址,使用 SOCKS 协议,即 SOCKS 代理服务器地址。

    2019-08-04 更新:需要注意的是,在 Windows 10 中,对于 socks5 代理常常出现失败的情况,即便勾选了Proxy DNS when using SOCKS v5,如果这样,请重启电脑试试;如果依然不行,勾选Enable DNS over HTTPS试试(关于 DoH 的更多信息可参见 在Firefox上开始使用DNS over HTTPS - 知乎

  3. 测试。打开新标签页->输入->回车
Google Chrome 浏览器的 SwitchyOmega 插件
  1. 安装 SwitchyOmega。请前往 SwitchyOmega - Chrome 网上应用商店(需要科学上网),对于不需要科学上网的安装方法,请使用必应百度搜索
  2. 新建类型为代理服务器情景模式。点击 Chrome 右上角的 SwitchyOmega 图标->点击选项->点击新建情景模式->输入一个你喜欢的情景模式名称->选择代理服务器->点击创建->选择代理协议SOCKS5->代理服务器中输入127.0.0.1->代理端口中输入1080->点击应用选项
  3. 使用刚刚创建的情景模式。点击 SwitchyOmega 图标(在浏览器右上角)->选中刚刚创建的情景模式
  4. 测试。打开新标签页->地址栏中输入->回车

笔者在 Windows 10 上测试,通过这种方法会默认使用 socks5 中的 HOSTNAME 字段,即默认会将 DNS 解析交给 SOCKS 代理服务器进行。所以通常可以成功访问谷歌

Firefox 浏览器的 FoxyProxy 插件

2019-07-04 更新:本部分的目标在于让浏览器根据浏览的网站的不同自动选择是否走代理,例如对于国外网站走代理,对于国内网站不走代理。方法也很简单,使用浏览器插件即可,FireFox 用 FoxyProxy,Chrome 用 SwitchyOmega。使用的过滤规则不是 PAC,而是 FoxyProxy 自制的规则

FoxyProxy 是 Firefox 浏览器中的一个非常好用的代理插件。因为有科学上网需求的主要是浏览器,且通常访问 Google 等国外网站较多,则可直接使用全局代理,对那少部分的需要访问的国内网站添加过滤规则(即 FoxyProxy 中的 Patterns)

  1. 安装FoxyProxy插件:https://addons.mozilla.org/en-US/firefox/addon/foxyproxy-standard/
  2. 设置FoxyProxy选项:
    1. Add Proxy: Proxy TypeSOCKS5IP address127.0.0.1Port1080,记得最后点下Save
    2. 添加Patterns: 在选项主界面,点击刚刚添加的ProxyPatterns,根据自己的需要添加Patterns
  3. 启用FoxyProxy:单击浏览器中右上角相应的图标,选择Use Enabled Proxies By Patterns and Priority
  4. 测试:输入网址www.google.com看是否访问成功
Kali 通过系统设置实现全局代理

2019-07-28 更新:本部分讲解在 Kali 中如何通过系统代理设置设置 socks5 代理

在系统设置中的网络代理方式设为手动,并将相应的Socks Host改为127.0.0.1 1080即可。具体步骤如下:

  1. 设置系统手动代理:设置->网络->网络代理,方式改为手动SOCKS Host改为127.0.0.1 1080,其它留空(留空的理由和前文类似)

    • HTTP ProxyHTTP 代理服务器地址。须知,使用前面的方法在127.0.0.1 1080处搭建的代理服务器是 SOCKS 代理服务器(不是 HTTP 代理服务器),且使用的是 socks5 协议(不是 socks4/socks4a 协议)。所以在这里填写127.0.0.1 1080将无法访问(即必须留空)
    • SSL Proxy:访问 HTTPS 站点时使用的代理服务器地址,其实就是 HTTP 代理服务器地址。留空原因同上
    • FTP Proxy:访问 FTP 站点时使用的代理服务器地址,其实就是 HTTP 代理服务器地址(不过需要注意的是 FTP 代理是存在的,例如使用工具ftp.proxy)。留空原因同上
    • SOCKS Host:访问任意站点时使用的代理服务器地址,使用 SOCKS 协议,即 SOCKS 代理服务器地址。

    温馨提示:该处的设置依赖于network-manager服务,应确保其正在运行。(有的人因为network-manager.servicenetworking.service冲突所以采取网上的建议将network-manager.service给禁用了,结果导致系统设置中和网络相关的设置均不可用。好吧,说的就是我自己-_-)可以使用systemctl命令查看network-manager.service的状态,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    root@kali:~# systemctl status network-manager.service 
    ● NetworkManager.service - Network Manager
       Loaded: loaded (/lib/systemd/system/NetworkManager.service; enabled; vendor preset: enabled)
       Active: active (running) since Thu 2019-07-04 23:30:33 CST; 19h ago
         Docs: man:NetworkManager(8)
     Main PID: 396 (NetworkManager)
        Tasks: 3 (limit: 4695)
       Memory: 13.8M
       CGroup: /system.slice/NetworkManager.service
               └─396 /usr/sbin/NetworkManager --no-daemon
       
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.6270] manager: NetworkManager state is now CONNECTED_GLOBAL
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7143] modem-manager: ModemManager available
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7188] device (eth0): state change: disconnected -> prepare (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7203] device (eth0): state change: prepare -> config (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7210] device (eth0): state change: config -> ip-config (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7215] device (eth0): state change: ip-config -> ip-check (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7226] device (eth0): state change: ip-check -> secondaries (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.7233] device (eth0): state change: secondaries -> activated (reason 'none', sys-iface-state: 'external')
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.8065] device (eth0): Activation: successful, device activated.
    7月 04 23:30:35 kali.abc.com NetworkManager[396]: <info>  [1562254235.8200] manager: startup complete
    root@kali:~# 
    

    另外,这一步中的设置完成后,每次打开新终端的时候,检查代理相关的环境变量,你会发现:

    1
    2
    3
    4
    5
    6
    
    root@kali:~# env|grep -i proxy
    ALL_PROXY=socks://127.0.0.1:1080/
    no_proxy=
    NO_PROXY=
    all_proxy=socks://127.0.0.1:1080/
    root@kali:~# 
    

    所以这个步骤的实质只是设置了下环境变量 :joy:

    假如你在系统的网络代理设置中将所有代理均设置为127.0.0.1 1080Ignore Hosts设置为127.0.0.1, 192.168.0.0/16,那么在新打开的终端中检查代理相关的环境变量,你会发现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    root@kali:~# env|grep -i proxy
    HTTP_PROXY=http://127.0.0.1:1080/
    FTP_PROXY=http://127.0.0.1:1080/
    https_proxy=http://127.0.0.1:1080/
    http_proxy=http://127.0.0.1:1080/
    ALL_PROXY=socks://127.0.0.1:1080/
    no_proxy=127.0.0.1,192.168.0.0/16
    NO_PROXY=127.0.0.1,192.168.0.0/16
    HTTPS_PROXY=http://127.0.0.1:1080/
    all_proxy=socks://127.0.0.1:1080/
    ftp_proxy=http://127.0.0.1:1080/
    root@kali:~# 
    

    同样印证了上述结论——在 Kali 系统设置中的网络代理设置处进行手动代理设置实质上是修改了代理相关的环境变量

    需要注意的是(如前文所述),通用代理只有两种:HTTP 代理(使用 http 协议)和 SOCKS 代理(使用 socks4/socks4a/socks5 协议)。即代理相关环境变量中,每个变量=后面的协议部分必需是http/socks4/socks4a/socks5之一(对于curl还支持socks5h,详情参见man curl中的--socks5-hostname 参数)

  2. 测试:打开浏览器,输入网址www.google.com看是否访问成功

2019-07-05 更新:如果使用的浏览器是 FireFox,则还需要将网络代理设置为Use system proxy settings(默认是这个,如果改过记得改回去)。同样要记得勾选下方的Proxy DNS when using SOCKS v5以防止 GFWDNS 污染

Kali 真·系统全局代理(透明代理)

2019-07-28 更新:本部分讲解在 Kali 中如何设置真正意义上的系统全局代理(即透明代理)。未实践过

如前所述,在 Kali 系统设置中的网络代理设置处进行手动代理设置实质上是修改了代理相关的环境变量。对于 linux 下不支持代理的程序而言,前面的设置并没有什么用,即并非真的实现了全局代理。那么如果要实现真正意义上的全局代理,即让所有应用都经过代理服务器该怎么办?答案是使用 tsocks:

tsocks 利用 LD_PRELOAD 机制,代理程序里的connect函数,然后就可以代理所有的 TCP 请求了。不过对于 dns 请求,默认是通过 udp 来发送的,所以 tsocks 不能代理 dns 请求。

默认情况下,tsocks 会先加载~/.tsocks.conf,如果没有,再加载/etc/tsocks.conf。对于 local ip 不会代理。

使用方法:

1
2
sudo apt-get install tsocks
LD_PRELOAD=/usr/lib/libtsocks.so wget http://www.facebook.com

——引用自科学上网的一些原理 | 横云断岭的专栏

关于 Linux 终端下程序的代理设置
终端代理环境变量

如前文所述,通用代理只有两种:HTTP 代理(使用 http 协议)和 SOCKS 代理(使用 socks4/socks4a/socks5 协议)。即代理相关环境变量中,每个变量=后面的协议部分必需是http/socks4/socks4a/socks5之一(对于curl还支持socks5h)。如下所示则全将其设置为了socks5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Set Proxy
function sp(){
    export all_proxy=socks5://127.0.0.1:1080/
    export ALL_PROXY=socks5://127.0.0.1:1080/ #有的命令行工具使用大写的变量名,如 curl
    export http_proxy=socks5://127.0.0.1:1080/ #有的命令行工具使用小写的变量名,如 curl、wget
    export ftp_proxy=socks5://127.0.0.1:1080/ #有的命令行工具使用小写的变量名,如 wget
    export FTP_PROXY=socks5://127.0.0.1:1080/ #有的命令行工具使用大写的变量名,如 curl
    export https_proxy=socks5://127.0.0.1:1080/ #有的命令行工具使用小写的变量名,如 wget
    export HTTPS_PROXY=socks5://127.0.0.1:1080/ #有的命令行工具使用大写的变量名,如 curl
    export no_proxy=localhost,127.0.0.1,192.168.0.0 #有的命令行工具使用小写的变量名,如 wget
    export NO_PROXY=localhost,127.0.0.1,192.168.0.0 #有的命令行工具使用大写的变量名,如 curl
}

# Unset Proxy
function up() {
    unset all_proxy ALL_PROXY http_proxy ftp_proxy FTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
}

其中的http_proxy表示访问http协议站点使用的代理,而不是使用http代理访问http协议站点。同理ftp_proxy表示访问ftp站点时使用的代理

使用程序的代理相关的参数
  1. git:已知(亲测)支持socks5http这两种代理方式,支持上述的终端代理环境变量。也可单独设置代理以覆盖全局设置:
    1
    2
    3
    4
    5
    6
    
    # 设置`socks5`代理
    git config --global http.proxy socks5h://127.0.0.1:1080
    # 设置`http`代理
    git config --global http.proxy http://127.0.0.1:1080
    # 取消代理
    git config --global --unset http.proxy
    

    对于socks5代理执行对应的git config命令后.gitconfig配置文件内容如下:

    1
    2
    
    [http]
        proxy = socks5h://127.0.0.1:1080
    

    其中socks5h(socks5 hostname)代表远程解析 DNS,这在大多数时候都是推荐选项,当然你也可以选择使用socks5。详情参见man curl中的--socks5-hostname介绍

    但是事实上,更建议这样设置:

    1
    
    git config --global http.https://github.com.proxy socks5h://127.0.0.1:1080
    

    这时配置文件~/.gitconfig内容如下:

    1
    2
    
    [http "https://github.com"]
        proxy = socks5h://127.0.0.1:1080
    

    另外需要注意的是,上述设置只能代理 remote-url 使用 HTTPS 协议的流量,如果你采用的是 SSH 协议,则上述设置无效,但是可通过修改 SSH 客户端配置文件来代理 SSH 流量(建议修改~/.ssh/config而非全局文件/etc/ssh/ssh_config)。添加如下内容即可::

    1
    2
    
    Host github.com
        ProxyCommand /usr/bin/ncat --proxy-type socks5 --proxy 127.0.0.1:1080 %h %p
    

    注意我使用的是 nmap 重新开发的工具nmap-ncat-6.40-16.el7.x86_64,而非原始的nc工具。如果使用原始的nc工具(netcat),可以这样:

    1
    2
    
    Host github.com
        ProxyCommand /usr/bin/nc -X 5 -x 127.0.0.1:1080 %h %p
    

    当然,Windows通常不会有nc命令,即便你安装了 Git Bash,但是有一个connect命令作为替代,因此可以这样:

    1
    2
    
    Host github.com
        ProxyCommand connect -S 127.0.0.1:1080 %h %p
    

    关于 git 设置代理的更多内容可参见 git 设置和取消代理

  2. curl:支持socks4socks4asocks5http这几种代理方式,支持上述的终端代理环境变量。也可单独设置代理以覆盖全局设置:

    1
    2
    
    curl -i4 -m3 -x socks5://192.168.56.11:1080 https://www.google.com
    curl -i4 -m3 -x socks5h://192.168.56.11:1080 https://www.google.com
    

    注意socks5socks5h的区别,前者解析域名时不使用代理,后者解析域名时要使用代理,由于国内 DNS 可能被污染,故建议使用socks5h。详情参见man curl

    –socks5-hostname <host[:port]>

    Use the specified SOCKS5 proxy (and let the proxy resolve the host name). If the port number is not specified, it is assumed at port 1080. (Added in 7.18.0)

    –socks5 <host[:port]>

    Use the specified SOCKS5 proxy - but resolve the host name locally. If the port number is not specified, it is assumed at port 1080.

    正因为 curl工具支持所有常用代理,我们可以利用它写个用于测试代理服务器是否正常工作的脚本:

    1
    2
    3
    4
    
    # test proxy
    function tp() {
    	curl -i -4 -m10 -s -x socks5h://$1:$2 https://www.google.com
    }
    

    将其添加至~/.bashrc末尾,通过如下方法使用:

    1
    
    tp 127.0.0.1 1080
    
  3. wget: 似乎只支持http协议代理,支持上述的终端代理环境变量。不可单独设置代理以覆盖全局变量

其它代理

该部分是笔者自己的理解,为了为后文作铺垫,仅供参考。

上述的两种代理(HTTPSOCKS)是极为常见的代理方式。但是它们都不提供额外加密(更不提供混淆)的功能,即如果要访问的目标服务器使用的是 HTTP 协议(明文传输,不安全),则客户端和代理服务器间的数据也是明文。因此如果在你(客户端)和你的 VPS(代理服务器)间使用 HTTPSOCKS 协议,那么 GFW 很容易检测到相关特征(如对于明文可以直接进行内容过滤、对于 HTTPS 可以使用 SNI 阻断等)。因此,就需要能对流量进行额外加密的代理协议,比如 SSHSSSSR、V2Ray 等等。这些正是后文要讲的内容

SSH, SS, SSR, V2Ray 在的原理总体上和上述的两种代理一样,都是由客户端发送数据到代理服务器,再由代理服务器向目标站点发出请求。但是在客户端这个地方有个本地代理(127.0.0.1 1080),这是上述的两种代理所没有的。原因也很简单,因为上述协议都比较复杂,浏览器等应用程序不可能实现它们的客户端(而浏览器等应用通常实现了 SOCKS 代理客户端,即将 HTTP 请求数据转换为 SOCKS 数据再发送给 SOCKS 代理服务器),所以需要一个独立的客户端应用程序作为中介,而这个中介就是所谓的本地代理(该客户端应用程序作为本地代理服务器)

对于 SSH (主要指它的动态端口转发,即-D参数)而言,这个中介就是 SSH 客户端,如 OpenSSH Client、PuTTY 等。由浏览器发出的数据通过浏览器本身将 HTTP 请求转换为 SOCKS 数据再发送给 SSH 客户端,再由 SSH 客户端将发来的数据加密通过 SSH 隧道传输到代理服务器,再由代理服务器向目标站点请求数据。

类似地,对于 SS 而言,这个中介就是 SS 客户端,例如用于 Windows 的 shadowsocks-windows,用于 Linux 的 shadowsocks-libev 中的ss-local等。由浏览器发出的数据通过浏览器本身将 HTTP 请求转换为 SOCKS 数据再发送给 SS 客户端,再由 SS 客户端将发来的数据加密,然后将加密后的数据发送到代理服务器,再由代理服务器向目标站点请求数据。

SSR、V2Ray 也类似,故不再赘述

SSH-D参数

简介

OpenSSHPuTTY都支持端口动态转发(即-D参数)。事实上,在 SSH 中,转发共有如下四种:

  • 本地端口转发:将发往本地端口的数据包通过 SSH 隧道转发到远程服务器的端口中,数据包由远程服务器处理。远程服务器可以 SSH 服务器自身,也可以是其它服务器(例如未加密的 HTTP 服务器,加密的 HTTPS 貌似会出于安全考虑拒收这样的数据包)。在sshplink/putty中均使用-L参数
  • 远程端口转发:将发往 SSH 服务器指定端口的数据通过 SSH 隧道转发到本地主机(客户端)的指定端口中,数据包由本地主机进行处理,然后反方向返回响应数据。在sshplink/putty中均使用-R参数
  • 动态端口转发:将发往本地端口的数据包通过 SSH 隧道发送到 SSH 服务器上,再由 SSH 服务器转发到目的地。具体流程如下:

    1. 在本地应用程序和本地端口间使用SOCK4/5协议进行通信(即本地 SOCKS 代理)
    2. 发送到本地端口的数据经过客户端程序ssh加密后发送到 SSH 服务器(即 SSH 加密后的数据通过网络传输)
    3. 服务器端程序sshd将其解密后再转发出去。

    在这种转发中,SSH 服务器用作代理服务器,即转发由客户端发送的数据包。这种转发在sshplink/putty中均使用-D参数

  • X 协议转发:以 GUI(图形用户界面)方式运行一些程序时会用到

关于它们的详细讲解请参见 实战 SSH 端口转发 。下面我们把重心放在第 3 种转发上(即动态端口转发),因为它完美满足了我们科学上网的需求。让我们先来看看它的运行原理

原理

动态端口转发原理图解 ——引用自 实战 SSH 端口转发

仔细看一下上面的图,让我们再来模拟一遍整个流程(假设浏览器的代理设置为socks5://127.0.0.1:7001,访问的 Web 服务器使用的是 HTTP 协议):

  1. 浏览器发送请求数据到本地主机的7001端口;
  2. 由本地主机上的ssh(客户端)处理该请求数据,将其加密;
  3. ssh(客户端)将加密后的数据发送给 SSH 服务器;
  4. 这个加密后的数据历经千难万险(如经过 GFW)到达服务器程序sshd
  5. sshd(服务器)将该数据解密;
  6. sshd(服务器)选择一个可用的端口(通常 10000+,因此被称为动态端口转发)将解密后的数据转发给目标服务器(在这里是 Web 服务器);
  7. Web 服务器收到解密后的请求数据返回相应的响应数据给 SSH 服务器;
  8. SSH 服务器收到响应数据后将其交给sshd处理;
  9. sshd将其加密后发送给客户端(期间经过 GFW);
  10. ……

清楚了这个 SSH -D参数的原理后对于后文理解 shadowsocks, shadowsocksr, V2ray 很有帮助。事实上,它们的基本原理几乎完全一样

现在再让我们来看一下 Linux 中的 manual 手册对该参数的说明:

-D port

This works by allocating a socket to listen to port on the local side, and whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.

——引用自man ssh

操作步骤

了解原理后,我们便可以使用如下命令实现动态端口转发:

1
2
ssh -N -D 1080 -p 22  <user>@<hostname> #for Linux/Windows + OpenSSH
plink -batch -N -D 1080 -load <your_saved_session> #for Windows + PuTTY

其中-N参数:

-NDo not execute a remote command. This is useful for just forwarding ports.

——引用自man ssh

执行完上述命令后,本地主机会在本地环回地址(127.0.0.1)的1080端口(当然,你也可以更换成其它端口)监听数据。如果监听到数据,就会将收到的数据加密并发送给 SSH 服务器,然后……(如原理中所述)

那么如何让1080端口监听到数据呢?答案很简单,只需设置全局代理(在 Windows 设置中),并将地址设置为127.0.0.1端口设置为1080即可让所有程序的数据都发送到1080端口

2019-07-18 更新:上述方法有问题。在 Windows 中,设置中的代理设置是通过修改 IE 中的代理设置实现的,且默认使用的是 HTTP 代理(不支持 sock5 代理,IE 代理设置处也只支持 socks4 代理)。作为替代,可使用 PAC 脚本。具体方法参见前文中的Windows 上使用 PAC 实现科学上网——情形二。另一个简单的方法是使用 Chrome + SwitchyOmega

当然你也可以使用前文提到的代理-SOCKS 代理中的在本地代理中的应用一节中的其它方法

可能遇到的问题

channel 1: open failed: administratively prohibited: open failed

These options can be found in /etc/ssh/sshd_config. You should ensure that:

  • AllowTCPForwarding is either not present, is commented out, or is set to yes
  • PermitOpen is either not present, is commented out, or is set to any[1]

Additionally, if you are using an SSH key to connect, you should check that the entry corresponding to your SSH key in ~/.ssh/authorized_keys does not have no-port-forwarding or permitopen statements[2].

——引用自 SSH tunneling error: “channel 1: open failed: administratively prohibited: open failed” - Unix & Linux Stack Exchange

小结

该方法非常简单,你甚至不需要在服务器上做任何配置,客户端的话ssh+一个浏览器插件即可,但前提在于你有一个在国外的服务器,并且每次使用都需要使用 ssh 连接你的服务器,故只适合特殊情况使用(比如你刚买/租用一个国外的服务器,并且迫切需要科学上网)。

2019-07-18 更新:事实上,你可以使用 Shell 脚本实现自动化。不过 SSH 的特征应该比 SS 等专用翻墙工具好检测

Shadowsocks

重要相关网站:

此方法截止 2018-10-20 已不可用。建议使用本文中的其它方法(可以逐个尝试)

2019-06-30 更新: 事实上,shadowsocks并非真的不可用了,毕竟现在 shadowsocks-libev 还在更新(其开发相当活跃),而且不少机场都是用的shadowsocks(如搬瓦工官方机场justmysocks)。所以当时我那个服务器上的shadowsocks不可用了应该另有其它原因。另外 2017 年 IHMSC 上发表的使用机器学习探测 shadowsocks 流量的论文存在争议

是什么

Shadowsocks(简称SS)是一种基于Socks5代理方式的加密传输协议,也可以指实现这个协议的各种开发包。当前包使用Python、C、C++、C#、Go语言等编程语言开发,大部分主要实现(iOS平台的除外)采用Apache许可证、GPLMIT许可证等多种自由软件许可协议开放源代码。Shadowsocks分为服务器端和客户端,在使用之前,需要先将服务器端程序部署到服务器上面,然后通过客户端连接并创建本地代理。

在中国大陆,本工具广泛用于突破防火长城(GFW),以浏览被封锁、遮蔽或干扰的内容。2015年8月22日,Shadowsocks原作者Clowwindy称受到了中国政府的压力,宣布停止维护此计划(项目)并移除其个人页面所存储的源代码。

为了避免关键词过滤,网民会根据谐音将ShadowsocksR称为“酸酸乳”(SSR),将Shadowsocks称为“酸酸”(SS)。

——引用自Shadowsocks - 维基百科,自由的百科全书

运行原理

Shadowsocks的运行原理与其他代理工具基本相同,使用特定的中转服务器完成数据传输。例如,用户无法直接访问Google,但代理服务器可以访问,且用户可以直接连接代理服务器,那么用户就可以通过特定软件连接代理服务器,然后由代理服务器获取网站内容并回传给用户,从而实现代理上网的效果。另外用户在成功连接到服务器后,客户端会在本机构建一个本地Socks5代理(或VPN、透明代理等)。浏览网络时,网络流量需要先通过本地代理传递到客户端软件,然后才能发送到服务器端,反之亦然。

为防止流量被识别和拦截,服务器和客户端软件会要求提供密码和加密方式,并且在数据传输期间会对传入和传出流量进行加密。

——引用自Shadowsocks - 维基百科,自由的百科全书

图解:

简单理解的话,shadowsocks 是将原来 ssh 创建的 Socks5 协议拆开成 server 端和 client 端,所以下面这个原理图基本上和利用 ssh tunnel 大致类似

shadowsocks原理图解

其中:

  • 1、6) 客户端发出的请求基于 Socks5 协议跟 ss-local 端进行通讯,由于这个 ss-local 一般是本机或路由器或局域网的其他机器,不经过 GFW,所以解决了上面被 GFW 通过特征分析进行干扰的问题
  • 2、5) ss-local 和 ss-server 两端通过多种可选的加密方法进行通讯,经过 GFW 的时候是常规的TCP包,没有明显的特征码而且 GFW 也无法对通讯数据进行解密
  • 3、4) ss-server 将收到的加密数据进行解密,还原原来的请求,再发送到用户需要访问的服务,获取响应原路返回

——引用自写给非专业人士看的 Shadowsocks 简介 | 綠茶如是说

因此,如果要使用 VPS 自行搭建 SS 服务并使用它,我们需要做如下几件事情:

  • VPS 服务器上搭建 SS 服务(对应上图中的SS Server):这个步骤可简单可复杂。想简单的话使用一键安装脚本即可,但是缺点在于你遇到问题后会一脸懵逼;复杂点的方法则是自己一步一步的根据官网指导,结合别人的博客来安装,缺点在于费时
  • 在客户端上进行配置(对应上图中的PCSS Local):对于 Windows, MacOS, Android 这几个操作系统来说这个过程是非常简单的。因为它们的客户端几乎都是带图形界面的(MacOS 也可以使用命令行),且近乎傻瓜式的操作在网上很容易找到带图的教程。而在 Linux 上则稍微麻烦些,不过现在也变得简单了,因为它也有了图形界面的客户端——shadowsocks-qt5,而且是跨平台的(因为 Qt5 这个图形界面接口是跨平台的)。但是,使用命令行更有助于了解原理

安全性

Shadowsocks的最初设计目的只是为了绕过GFW,而不是提供密码学意义的安全,所以Shadowsocks自行设计的加密协议对双方的身份验证仅限于预共享密钥,亦无完全前向保密,也未曾有安全专家公开分析或评估协议及其实现。如果是在监听类型的国家内想更加安全的上网,基本上Shadowsocks功能不够完善,应该使用隐密性更高的工具。[8]

Shadowsocks本质上只是设置了密码的专用网络代理协议,不能替代TLS或者VPN,不能用作匿名通信方案,该协议的目标不在于提供完整的通信安全机制,主要是为了协助上网用户在严苛的网络环境中突破封锁。

在某些极端的环境下,通过深度包检测(DPI)也有可能识别出协议特征。为了确保安全,用户应做好额外的加密和验证措施,以免泄露信息,无论使用的服务器来源是否可靠。2017年9月21日,一篇名为《The Random Forest based Detection of Shadowsock’s Traffic》的论文在IEEE发表,该论文介绍了通过随机森林算法检测Shadowsocks流量的方法,并自称可达到85%的检测精度[9],虽然该论文的有效性遭到网友质疑[10],但机器学习配合GFW已经实现的深度数据包检测来识别网络流量特征的做法是实际可行的,而且还适用于任何网络代理协议而不仅仅局限于Shadowsocks。[11]

——引用自Shadowsocks - 维基百科,自由的百科全书

实现

当前Shadowsocks有多个实现支持,以自由软件形式发布的主要有原始Shadowsocks(以Python语言编写)、Shadowsocks-libev(分支项目openwrt-Shadowsocks)、Shadowsocks-rust、Shadowsocks-go/go-Shadowsocks2、libQtShadowsocks、Shadowsocks-qt5(仅作为客户端)、Shadowsocks-android(仅作为客户端)、Shadowsocks-windows(仅作为客户端)、ShadowsocksX-NG(仅作为客户端)、Outline[12]、V2Ray、Brook[13]等等,还有为数甚多的免费软件及专有软件。

——引用自Shadowsocks - 维基百科,自由的百科全书

相对官方的实现请参见: Shadowsocks - Implementations

使用方法

环境说明

  • 服务器操作系统:CentOS7.2
    • 使用的 shadowsocks 实现(服务器):shadowsocks-libev
    • 使用的用户:root
  • 客户端操作系统:Kali-Linux
    • 使用的 shadowsocks 实现(客户端):shadowsocks-qt5
    • 使用的用户:root

值得注意的是上面的服务器和客户端用的软件不一样,但是重要的不是软件表面,而是它们的“内涵”,它们都是使用的 shadowsocks 协议,只不过 shadowsocks-libev(C语言、轻量、快速、开发活跃) 通常用作服务器端(也可用作客户端),shadowsocks-qt5(C++、图形界面、跨平台) 只能用做客户端

另外,对于其它操作系统和实现,参考相应的官网文档操作即可。它们的官网链接在Shadowsocks - Implementations页面中

这里还有份来自别的博客的对shadowsocks-libev的简介:

shadowsocks-libev 是一个 shadowsocks 协议的轻量级实现,是 shadowsocks-android, shadowsocks-ios 以及 shadowsocks-openwrt 的上游项目。其具有以下特点:

  • 体积小巧,静态编译并打包后只有 100 KB
  • 高并发,基于 libev 实现的异步 I/O,以及基于线程池的异步 DNS,同时连接数可上万。
  • 低资源占用,几乎不占用 CPU 资源,服务器端内存占用一般在 3MB 左右。
  • 跨平台,适用于所有常见硬件平台,已测试通过的包括 x86,ARMMIPS。也适用于大部分 POSIX 的操作系统或平台,包括 Linux,OS X 和 gwin 等。
  • 协议及配置兼容,完全兼容 shadowsocks 协议,且兼容标准实现中的 JSON 风格配置文件,可与任意实现的 shadowsocks 端或服务端搭配使用。

——引用自CentOS 7 配置 shadowsocks-libev 服务器端进行科学上网 | 鸣沙山侧 月牙泉畔

服务器配置(SS Server)

两个方法,使用脚本一键安装和手动安装。前者非常简单,后者较为困难,且不同 Linux 发行版可能不一样

一键安装脚本可在 teddysun/shadowsocks_install at master 获得。注意,因为“某些”原因,该一键安装脚本已经停止更新,参见 Shadowsocks非官方网站

下面详细讲解手动安装的方法(注意操作系统为 CentOS7.2,使用的实现为 shadowsocks-libev)

安装shadowsocks-libev
方法一:添加 librehat-shadowsocks-epel 源
1
2
3
4
5
cd /etc/yum.repos.d/ #进入 CentOS 软件源目录
wget https://copr.fedorainfracloud.org/coprs/librehat/shadowsocks/repo/epel-7/librehat-shadowsocks-epel-7.repo #下载librehat-shadowsocks 软件源
yum install epel-release #安装额外的软件源(shadowsocks-libev的依赖 libsodium 和 mbedtls 要用)
yum makecache fast #更新软件缓存信息(类似 apt update)
yum install shadowsocks-libev #安装

其中,如果安装了 epel-release 依然显示找不到 libsodiummbedtls ,则可以使用命令yum reinstall epel-release重新安装

详情参见Install from repository

温馨提示:通过这种方法安装的shadowsocks-libev的版本为3.2.0(2018年5月发布(参见shadowsocks/shadowsocks-libev at v3.2.0))。如果想要安装最新版本(当前(2019-07-01)为3.3.0)),建议使用从源码编译的方法,即后文中的方法二

方法二:从源码编译安装(推荐)

参考自 shadowsocks libev · iMeiji/shadowsocks_install Wiki

1
2
3
4
5
6
yum install epel-release -y #安装额外的软件源(shadowsocks-libev的依赖 libsodium 和 mbedtls 要用)
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y #安装依赖
git clone https://github.com/shadowsocks/shadowsocks-libev.git #克隆源代码到本地
cd shadowsocks-libev #进入目录
./autogen.sh && ./configure && make #开始构建(编译)
sudo make install #安装
方法三:生成 RPM 文件安装(推荐)
1
2
3
4
5
git clone https://github.com/shadowsocks/shadowsocks-libev.git #克隆源代码到本地
cd shadowsocks-libev/rpm/ #进入 rpm 目录
./genrpm.sh -b #可通过 -h 参数查看帮助
cd RPMS/x86_64/
yum install shadowsocks-libev-3.3.0-1.21.gite3c6c80.el7.x86_64.rpm #从生成的 RPM 文件安装
方法四:从 SRPM 文件安装(不推荐)

该方法主要是为了涨知识,较繁琐,不实用

1
2
3
git clone https://github.com/shadowsocks/shadowsocks-libev.git #克隆源代码到本地
cd shadowsocks-libev/rpm/ #进入 rpm 目录
./genrpm.sh #可通过 -h 参数查看帮助

此时在SRPMS/目录中便有相应的 SRPM 文件了,通过我另一篇博客中的方法将其转换为 RPM 文件以安装——rpm相关#重建-srpm

概览shadowsocks-libev包中的文件

安装好后让我们来看一下shadowsocks-libev软件包展开后都有哪些文件(使我们对这个软件包有着更清晰的认识):

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
# rpm -ql shadowsocks-libev
/etc/shadowsocks-libev/config.json
/etc/sysconfig/shadowsocks-libev
/usr/bin/ss-local
/usr/bin/ss-manager
/usr/bin/ss-nat
/usr/bin/ss-redir
/usr/bin/ss-server
/usr/bin/ss-tunnel
/usr/lib/systemd/system/shadowsocks-libev-local.service
/usr/lib/systemd/system/shadowsocks-libev-local@.service
/usr/lib/systemd/system/shadowsocks-libev-redir@.service
/usr/lib/systemd/system/shadowsocks-libev-server@.service
/usr/lib/systemd/system/shadowsocks-libev-tunnel@.service
/usr/lib/systemd/system/shadowsocks-libev.service
/usr/lib64/libshadowsocks-libev.la
/usr/lib64/libshadowsocks-libev.so
/usr/lib64/libshadowsocks-libev.so.2
/usr/lib64/libshadowsocks-libev.so.2.0.0
/usr/lib64/pkgconfig
/usr/lib64/pkgconfig/shadowsocks-libev.pc
/usr/share/doc/shadowsocks-libev
/usr/share/doc/shadowsocks-libev/shadowsocks-libev.html
/usr/share/doc/shadowsocks-libev/ss-local.html
/usr/share/doc/shadowsocks-libev/ss-manager.html
/usr/share/doc/shadowsocks-libev/ss-nat.html
/usr/share/doc/shadowsocks-libev/ss-redir.html
/usr/share/doc/shadowsocks-libev/ss-server.html
/usr/share/doc/shadowsocks-libev/ss-tunnel.html
/usr/share/man/man1
/usr/share/man/man1/ss-local.1.gz
/usr/share/man/man1/ss-manager.1.gz
/usr/share/man/man1/ss-nat.1.gz
/usr/share/man/man1/ss-redir.1.gz
/usr/share/man/man1/ss-server.1.gz
/usr/share/man/man1/ss-tunnel.1.gz
/usr/share/man/man8
/usr/share/man/man8/shadowsocks-libev.8.gz

可以看到其最主要的配置文件(/etc/...)应该是/etc/shadowsocks-libev/config.json,其最常用的命令(/usr/bin/...)应该是ss-server(用于服务器),其次应是ss-local(用于客户端)。此外,可以通过systemctl命令(/usr/lib/systemd/system/...)实现对所有命令的控制,如:

1
2
systemctl enable shadowsocks-libev-local@client
systemctl enable shadowsocks-libev-server@server

其中client表示/etc/shadowsocks-libev/client.jsonserver类似,不使用config是为了避免混乱,毕竟服务器和客户端所使用的配置文件还是不一样的

另外其还有静态和动态运行库(/usr/lib64/...,其中*.la表示静态库,*.so表示动态库)。最后其文档也是相当完善的,有用于man命令的在线手册(/usr/share/man/...),也有html格式的网页(/usr/share/doc/...)。因此,强烈建议至少通读一下man 8 shadowsocks-libev

配置shadowsocks-libev

由于在服务器端只使用ss-server,所以我们直接修改默认的配置文件/etc/shadowsocks-libev/config.json即可:

1
2
3
4
5
6
7
8
9
{
    "server":"0.0.0.0",
    "server_port":1234,
    "local_address": "0.0.0.0",
    "local_port":1080,
    "password":"shadowsocks",
    "timeout":60,
    "method":"aes-256-cfb"
}

其中local_address字段和local_port字段可省略(它们是用于客户端的)。需要注意的是端口千万不要设置为默认的8388,因为现在的 GFW 好像会阻断端口8388的连接(毕竟用 shadowsocks 的人太多了)

控制shadowsocks-libev

使用如下命令启动:

1
systemctl start shadowsocks-libev-server@config

使用如下命令设置开机自启:

1
systemctl enable shadowsocks-libev-server@config

使用如下命令查看状态:

1
systemctl status shadowsocks-libev-server@config

使用如下命令停止:

1
systemctl stop shadowsocks-libev-server@config
查看日志

可以在/var/log/messages中查看相关日志,也可以使用journalctl -u shadowsocks-libev-server@config命令查看

关于将shadowsocks-libev用作客户端

其实如果使用shadowsocks-libev作为客户端也是极为简单的,其配置文件只需更改server字段即可。如对于上述配置的服务器,客户端可以使用如下配置文件(假设命名为client.json):

1
2
3
4
5
6
7
8
9
{
    "server":"serverip",
    "server_port":1234,
    "local_address": "0.0.0.0",
    "local_port":1080,
    "password":"shadowsocks",
    "timeout":60,
    "method":"aes-256-cfb"
}

使用如下命令启动:

1
systemctl start shadowsocks-libev-local@client

使用如下命令设置开机自启:

1
systemctl enable shadowsocks-libev-local@client

……

客户端配置(SS Local + PC

  • 客户端操作系统:Kali Linux 2.0
  • 使用的 shadowsocks 实现(客户端):shadowsocks-qt5
  • 使用的用户:root

2019-07-02更新: 客户端选择shadowsocks-qt5是因为它简单,界面友好(好吧,是因为当初只听说过它)。现在的我更倾向于使用shadowsocks-libev作为客户端,因为它最近一次更新在 2019 年 7 月,而 shadowsocks(即原始的 Python 版)最后更新时间是 2018 年 10 月,shadowsocks-qt5 最近一次更新则是在 2018 年 8 月

安装并配置shadowsocks-qt5SS Local 连接到 SS Server)
  1. /etc/apt/sources.list文件末尾添加: deb http://ppa.launchpad.net/hzwhuang/ss-qt5/ubuntu devel main
  2. 更新 apt 软件列表:
    1
    2
    3
    4
    
     apt update #这里会提示错误,以下两步解决该错误
     gpg --keyserver keyserver.ubuntu.com --recv 6DA746A05F00FA99
     gpg --export --armor 6DA746A05F00FA99 | sudo apt-key add -
     apt update #这一步成功后便可安装shadowsocks-qt5了
    
  3. 安装shadowsocks-qt5: apt install shadowsocks-qt5

  4. 安装后在bash中输入ss-qt5, 完成配置, 配置好后的图如下:

    ss-qt5

设置 PAC 自动代理(PC 连接到 SS Local)
  1. 获得 pac 文件:

    1
    2
    3
    4
    5
    6
    
      pip install genpac
      pip install --upgrade genpac
      mkdir ~/vpnPAC
      cd ~/vpnPAC
      touch user-rules.txt
      genpac -p "SOCKS5 127.0.0.1:1080" --gfwlist-proxy="SOCKS5 127.0.0.1:1080" --output="autoproxy.pac" --gfwlist-url="https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt" --user-rule-from="user-rules.txt"
    
  2. 系统设置自动代理: 设置->网络->网络代理方式改为自动配置URL改为:file://root/vpnPAC/autoproxy.pac

2019-08-04 更新:关于 PAC 的更多内容可以参见前文的 PAC 部分。此外,除了这里的 PAC 自动代理,还可参见前文的 代理-SOCKS 代理中的在本地代理中的应用部分达到配置本地代理的目的

优化
  1. 设置开机启动:通过kali linux自带的优化工具实现: Win+a, 直接输入优化工具,出现优化工具图标(当然你也可以自己找),双击,找到开机启动程序,添加shadowsock-qt5
  2. 自动连接某个节点:打开bash,输入ss-qt5右键某个节点->编辑->程序启动时自动连接
  3. 通过快捷键开启或关闭shadowsocks-qt5: 设置->键盘->添加自定义快捷键(滑到最下面你会看到一个+), 名字可以随意,命令输入ss-qt5(关闭时输入pkill ss-qt5),按键设置成你喜欢的即可。

shadowsocksr

  • 该方法最初发布时间:2018-10-20
  • 该方法最后更新时间:2019-07-03。此次更新添加了一些新内容(重要相关网站、简介、基本原理、安全性、实现、服务器配置、2019-07-03 更新),并对之前的部分内容进行了优化

重要链接:

主要是因为 SS 不能用了,所以把服务器改成了 SSR 的。而 Linux 下的 SSR 客户端配置起来有点麻烦,故更新此文,添加了该内容。

起初我以为最简单的方法为使用electron-ssr,因为它看起来那么的棒,结果安装后却只有第一次可以成功打开,不知是它的 BUG 还是kali的 BUG 。

2019-07-03 更新:2019 年 05 月 15 日 electron-ssr 原作者 erguotou520 因为在 Telegram 群里听说 Doubi 被抓,自行删库。参见 format · erguotou520/bye@7541a9aShadowsocks非官方网站。现在其项目由 shadowsocksrr 维护,且最近一次更新是在2019 年 5 月,所以可能还能用,大家可以低调地试试

后来根据Python版SSR客户端4 - Ubuntu 16.04 + SSR翻墙这两个参考链接才成功,下面简要总结如下:

2019-07-03 更新:上面的两个参考链接中,第二个参考链接已失效

简介

ShadowsocksR(简称SSR)是网名为breakwa11的用户发起的Shadowsocks分支,在Shadowsocks的基础上增加了一些数据混淆方式,称修复了部分安全问题并可以提高QoS优先级。[20]后来贡献者Librehat也为Shadowsocks补上了一些此类特性,[21]甚至增加了类似Tor的可插拔传输层功能。[22]

——引用自Shadowsocks#ShadowsocksR - 维基百科,自由的百科全书

需要注意的是其原开发者 breakwa11 已删除了 GitHub 上的所有 ShadowsocksR 代码、解散了相关 Telegram 交流群组,停止开发 ShadowsocksR 项目。但该项目已被多人 fork,并有人在其基础上继续发布新的版本,例如较为知名的 SSRR (ShadowsocksRR)。而本部分(shadowsocksr)讲解的也正是 SSRR

基本原理

由于其前身是 shadowsocks,所以它的基本原理和 shadowsocks 相同,依然可以用前文所述的方法解释,只是将 SS 替换为 SSR 即可:

简单理解的话,shadowsocks 是将原来 ssh 创建的 Socks5 协议拆开成 server 端和 client 端,所以下面这个原理图基本上和利用 ssh tunnel 大致类似

shadowsocks原理图解

其中:

  • 1、6) 客户端发出的请求基于 Socks5 协议跟 ss-local 端进行通讯,由于这个 ss-local 一般是本机或路由器或局域网的其他机器,不经过 GFW,所以解决了上面被 GFW 通过特征分析进行干扰的问题
  • 2、5) ss-local 和 ss-server 两端通过多种可选的加密方法进行通讯,经过 GFW 的时候是常规的TCP包,没有明显的特征码而且 GFW 也无法对通讯数据进行解密
  • 3、4) ss-server 将收到的加密数据进行解密,还原原来的请求,再发送到用户需要访问的服务,获取响应原路返回

——引用自写给非专业人士看的 Shadowsocks 简介 | 綠茶如是说

因此,如果要使用 VPS 自行搭建 SS 服务并使用它,我们需要做如下几件事情:

  • VPS 服务器上搭建 SS 服务(对应上图中的SS Server):这个步骤可简单可复杂。想简单的话使用一键安装脚本即可,但是缺点在于你遇到问题后会一脸懵逼;复杂点的方法则是自己一步一步的根据官网指导,结合别人的博客来安装,缺点在于费时
  • 在客户端上进行配置(对应上图中的PCSS Local):对于 Windows, MacOS, Android 这几个操作系统来说这个过程是非常简单的。因为它们的客户端几乎都是带图形界面的(MacOS 也可以使用命令行),且近乎傻瓜式的操作在网上很容易找到带图的教程。而在 Linux 上则稍微麻烦些,不过现在也变得简单了,因为它也有了图形界面的客户端——shadowsocks-qt5,而且是跨平台的(因为 Qt5 这个图形界面接口是跨平台的)

——引用自前文的SS 运行原理

安全性

简介中所述:

在 Shadowsocks 的基础上增加了一些数据混淆方式,称修复了部分安全问题并可以提高 QoS 优先级

实现

和 shadowsocks 类似,不过其开发并不活跃。结合 Shadowsocks - ImplementationsGitHub - shadowsocksrr可以知晓它的实现和 SS 的对应关系。

需要注意的是有的实现很长时间没有更新了,下表列出其各个实现的最近一次更新时间(2019-07-03):

实现 编程语言 适用平台 最近一次更新 服务器 or 客户端
shadowsocksr Python Linux, OSX 2018-05 both
shadowsocksr-libev C Linux, OSX, openwrt 2018-03 both
shadowsocksr-android Java,Go Android 2018-03 client
shadowsocks-csharp C# Windows 2019-04 client
SSR-Windows(forked from shadowsocks-csharp) C# Windows 2018-08 client
electron-ssr JavaScript, Vue Linux, OSX, Windows 2019-05 client

上述所有信息来源于 shadowsocksrr

温馨提示:对于 shadowsocksr-csharp(Windows SSR 客户端)而言,它的本地代理是个全能代理,同一端口支持socks4/socks4a/socks5/http(通过 privoxy)(参见 BRITE’S BLOG.人生在世,看得穿,又看得远者prevail everywhere.: ShadowsocksR CSharp

注意其中的服务器和客户端一栏,通常而言,可用于服务器端的话就能用于客户端,所以 shadowsocksr 和 shadowsocks-libev 均为both。此外令人震惊的是,上述所有软件的最近一次更新全是由 Akkariiin (Akkariiin) 完成的,当然,也可能只是因为他恰好负责打包和发布这一工作。无论如何,在此表示敬意和感谢

使用方法

服务器配置(SSR Server)

使用一键安装脚本 teddysun/shadowsocks_install at master

回头有空再补充手动安装的方法

客户端配置(SSR Local + PC

环境说明
  • 操作系统:Kali Linux。实际上只要是 Linux 将本文内容稍加修改也适用。毕竟核心的东西是不变的
  • 使用的 SSR 客户端:shadowsocksr(Python 版)。
SSR Local 连接到 SSR Server

2019-07-05 更新: 该部分阐述了如何让 SSR Local 连接到 SSR Server。在 SSR Local 和 SSR Server 通信的过程中使用的协议为 SSR

之所以使用 Python 版,是因为我只找到 Python 版的,/笑哭。 这一步是最重要的,后面的方法都建立在这个基础之上

2019-07-03 更新:事实上,SSR 现在可用的 Linux 客户端有三个,shadowsocksr, shadowsocksr-libev, electron-ssr,参见前面的 SSR 实现部分

  1. 获得 Python 版 SSR 的相关文件:
    1
    2
    
    cd ~/
    git clone https://github.com/shadowsocksrr/shadowsocksr
    

    经测试,其实只有 shadowsocksr 下的 shadowsocks 目录是必须的

  2. 根据你的服务器配置修改配置文件~/shadowsocksr/config.json:
    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
    
    {
        "server": "<ip address>",
        "server_ipv6": "::",
        "server_port": 8388,
        "local_address": "127.0.0.1",
        "local_port": 1080,
       
        "password": "password",
        "method": "none",
        "protocol": "auth_chain_a",
        "protocol_param": "",
        "obfs": "plain",
        "obfs_param": "",
        "speed_limit_per_con": 0,
        "speed_limit_per_user": 0,
       
        "additional_ports" : {},
        "additional_ports_only" : false,
        "timeout": 120,
        "udp_timeout": 60,
        "dns_ipv6": false,
        "connect_verbose_info": 0,
        "redirect": "",
        "fast_open": false
    }
    
  3. 启动SSR客户端:
    1
    2
    
    cd ~/shadowsocksr/shadowsocks
    python2 local.py -c ~/shadowsocksr/config.json
    
  4. 测试:暂时无法测试(欢迎知道的人告诉我此处应如何测试)
  5. 自动化:将如下bash脚本添加到~/.bashrc文件中(我自己写的,欢迎提建议):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    function pg(){
      ps aux | grep -v "grep" |grep $1 
    }
    function ssr(){
    	ps aux |grep "[l]ocal\.py" > /dev/null
    	if [ $? -eq 1 ]; then
    		python ~/shadowsocksr/shadowsocks/local.py -c ~/shadowsocksr/config.json -d start
    	else
    		if [ -n "$1" ]; then
    			kill `pg "local\.py" | awk '{print $2}'`
    		else
    			echo "ssr has been run!"
    		fi
    	fi
    }
    ssr
    

    简要说一下上面那个函数ssr的用法:直接在 bash 中输入ssr后回车则后台启动(关闭终端也能继续运行)ssr客户端,输入ssr <任意字符>则关闭已启动的ssr客户端。

PC 连接到 SSR Local

实际上就是设置 SOCKS 本地代理,参见前文中的代理部分的 PACSOCKS 代理 的相关内容

V2Ray

V2Ray 是一个非常强大的存在,其多入口多出口的设计理念导致它可以衍变出很多种科学上网方案,并且易于拓展,原理清晰。是深入学习和研究的首选工具

重要链接:

简介

SSSSR 不同,V2Ray 是新兴势力(2015.11.30 v1.0),因此其开发活跃,文档丰富

Project V 是一个工具集合,它可以帮助你打造专属的基础通信网络。Project V 的核心工具称为V2Ray,其主要负责网络协议和功能的实现,与其它 Project V 通信。V2Ray 可以单独运行,也可以和其它工具配合,以提供简便的操作流程。

——引用自Project V · Project V 官方网站

V2Ray 自行设计了Vmess应用层协议和mKCP传输层协议,所以建议使用它们。当然,你也可以选择它支持的其它协议(如 SS

主要特性

  • 多入口多出口: 一个 V2Ray 进程可并发支持多个入站和出站协议,每个协议可独立工作。
  • 可定制化路由: 入站流量可按配置由不同的出口发出。轻松实现按区域或按域名分流,以达到最优的网络性能。
  • 多协议支持: V2Ray 可同时开启多个协议支持,包括 Socks、HTTP、Shadowsocks、VMess 等。每个协议可单独设置传输载体,比如 TCP、mKCP、WebSocket 等。
  • 隐蔽性: V2Ray 的节点可以伪装成正常的网站(HTTPS),将其流量与正常的网页流量混淆,以避开第三方干扰。
  • 反向代理: 通用的反向代理支持,可实现内网穿透功能。
  • 多平台支持: 原生支持所有常见平台,如 Windows、Mac OS、Linux,并已有第三方支持移动平台。
  • 总体原理和 SS 类似,不再赘述。不过它更复杂,更灵活,但是却不混乱,模块划分很合理

——引用自Project V · Project V 官方网站

工作原理

在配置 V2Ray 之前,不妨先来看一下 V2Ray 的工作原理,以下是单个 V2Ray 进程的内部结构示意图。多个 V2Ray 之间互相独立,互不影响。

V2Ray工作原理.png

  • 需要配置至少一个入站协议(Inbound)和一个出站协议(Outbound)才可以正常工作。协议列表见第二章节。
    • 入站协议负责与客户端(如浏览器)通信:
      • 入站协议通常可以配置用户认证,如 ID 和密码等;
      • 入站协议收到数据之后,会交给分发器(Dispatcher)进行分发;
    • 出站协议负责将数据发给服务器,如另一台主机上的 V2Ray。
  • 当有多个出站协议时,可以配置路由(Routing)来指定某一类流量由某一个出站协议发出。
    • 路由会在必要时查询 DNS 以获取更多信息来进行判断。

——引用自Project V · Project V 官方网站

安全性

TODO

实现

V2ray core(官方) + GUI(其它)。

官方实现的是核心模块 V2Ray core,没有图形界面,但基本够用;其它实现使用官方的 V2Ray core 作为后端,制作了很多图形界面,具体参见 神一样的工具们 · Project V 官方网站

使用方法

参见官方文档 下载安装 · Project V 官方网站

由于其相关的文档(主要是指官方文档白话文教程)做得很好,所以没有必要再赘述一遍,重复造轮子

需要注意的是,官方安装脚本不支持 CentOS 6.x 等较老版本的基于 redhat 的操作系统,但是只需稍作更改即可。主要问题出在官方安装脚本go.sh中的installInitScript函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
installInitScript(){
    if [[ -n "${SYSTEMCTL_CMD}" ]];then
        if [[ ! -f "/etc/systemd/system/v2ray.service" ]]; then
            if [[ ! -f "/lib/systemd/system/v2ray.service" ]]; then
                cp "${VSRC_ROOT}/systemd/v2ray.service" "/etc/systemd/system/"
                systemctl enable v2ray.service
            fi
        fi
        return
    elif [[ -n "${SERVICE_CMD}" ]] && [[ ! -f "/etc/init.d/v2ray" ]]; then
        installSoftware "daemon" || return $?
        cp "${VSRC_ROOT}/systemv/v2ray" "/etc/init.d/v2ray"
        chmod +x "/etc/init.d/v2ray"
        update-rc.d v2ray defaults
    fi
    return
}

在执行installSoftware "daemon"时会出现找不到安装包的情况,daemon应该是 Ubuntu 等基于 debian 的发行版才有的软件包。所以剩下的步骤需要手动:

  1. 安装chkconfig。CentOS 6.x 不使用 systemctl,也不使用 update-rc.d 管理自启动的服务,它使用的是chkconfig,且通常已经安装好了,如果没有安装,执行如下命令安装;
    1
    
    yum install chkconfig
    
  2. 获取正确的init.d相关文件。参见 https://github.com/v2ray/v2ray-core/issues/101#issuecomment-214670792。将其复制为/etc/init.d/v2ray(而不是使用${VSRC_ROOT}/systemv/v2ray

  3. /etc/init.d/v2ray添加可执行权限。
    1
    
    chmod +x "/etc/init.d/v2ray"
    
  4. 设置开机自启。
    1
    
    chkconfig v2ray on
    

注意事项

  1. 客户端与服务器的时间相差不能超过90秒钟,否则可能出现VMess: Invalid UserERR_CONNECTION_CLOSED等错误

Vmess + WS + CDN

直接封 VPSIP 地址是 GFW 的一大杀手锏,因为 IP 被封后,VPS 上搭建的所有服务都不能被直接访问(事实上连 ping 都 ping 不通)。好在,使用 CDN 可以完美地解决这个问题

(主要是因为 SSR 不能用了(原因在于 2019-06-01 左右 IP 被封),所以在网上找到了这个方案)

重要链接:

简介

该方案的核心是 CDN。因此我们先来看看什么是 CDN

CDN

内容分发网络(英语:Content Delivery Network或Content Distribution Network,缩写:CDN)是指一种透过互联网互相连接的计算机网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、影片、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。

——引用自内容分发网络 - 维基百科,自由的百科全书

CDN 最初用于加速访问 Web 网站的静态内容,如 HTML 文档、图片等。而下面我们将要使用的 CDN 算是某种程度上的妙用

除了 CDN 外,该方案还会用到 WS(WebSocket)。为什么要使用 WS 呢?如前所述,CDN 主要用于加速访问 Web 网站的静态内容,而这些内容通常都是使用 Web 相关的协议(如 HTTP, HTTP/2, WebSocket 等)进行访问,为了使用 CDN,我们需要伪装为 Web 相关的流量。

那么我们为什么不伪装成 HTTP 或者 HTTP/2 呢?对于 HTTP,我能想到的一个可能的原因是使用 HTTPCDN 只支持静态内容,但是我们要用的是动态的,在 CDN 上根本就不会有缓存(待例证及进一步分析);而对于 HTTP/2,则是因为 cloudflare 不完全支持 HTTP/2 1

总之,我们选择了 WebSocket,那么 WebSocket 是什么呢?

WebSocket

WebSocket是一种通信协议,可在单个TCP连接上进行全双工通信。WebSocket协议在2011年由IETF标准化为RFC 6455,后由RFC 7936补充规范。Web IDL中的WebSocket API由W3C标准化。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

——引用自WebSocket - 维基百科,自由的百科全书

关于 WebSocket 的更多内容,还可以参考 WebSocket 教程 - 阮一峰的网络日志

具体步骤

参见 拯救被墙的IPCDN + v2ray,安全的科学上网方法 | sprov(以 cloudflare 为例)。

我使用的便是该教程。只不过其中的二级域名我用的是花生壳(oray)的(因为之前我用过它的壳域名)而不是 godaddy 的。花生壳注册域名需要实名认证,而 godaddy 不需要,所以事实上更推荐 godaddy 或者其它国外的域名注册站点,我当初只是年少无知,以为注册域名都需要实名认证 :joy:

下面根据该教程总结了一下大概步骤:

  1. 购买一个二级域名。例如wsxq2.top。下面列几个购买站点:
    • 国外:
      1. godaddy(全球最大)
      2. namesilo(价格最低)
      3. namecheap(口碑最好)
        1. oray
        2. dnspod
  2. 选择一个 CDN 服务提供商并添加二级域名站点。例如在添加站点处输入wsxq2.top。下面列几个 CDN 服务提供商站点:
    1. cloudflare(CF)
    2. 腾讯
    3. 又拍云(专业,较贵)
    4. 阿里(较便宜),具体步骤可参见V2Ray套阿里云CDN:差点翻车,常规方法走不通
    5. NodeCache
    6. 知道创宇
  3. 在购买域名的站点配置 DNS。设置域名服务器为 CDN 服务提供商提供的域名服务器地址。例如将 orayNS 管理 处的 设置自定义 DNS 配置为derek.ns.cloudflare.comgail.ns.cloudflare.com

  4. CDN 服务提供商处配置 DNS 解析记录。例如在 cloudflareDNS 处添加如下记录:
    1
    
    A www 93.179.128.98 Auto Proxied
    
  5. 配置 V2Ray 服务端。配置文件样例(放在inbounds数组中):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    {
      "protocol": "vmess",
        "port": 80,
        "streamSettings":{
          "wsSettings":{
            "path":"/",
            "headers":{}
          },
          "network":"ws"
        },
        "settings": {
          "clients": [
          {
            "id": "使用自己的 ID",
            "level": 1,
            "alterId": 4
          }
          ]
        }
    }
    
  6. 配置 V2Ray 客户端。配置文件样例(放在outbounds数组中):
    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
    
    {
      "protocol": "vmess",
      "tag": "out_vmess",
      "streamSettings": {
        "wsSettings": {
          "path": "/",
          "headers": {}
        },
        "network": "ws"
      },
      "settings": {
        "vnext": [
          {
            "address": "www.wsxq2.top",
            "port": 80,
            "users": [
              {
                "id": "使用自己的 ID",
                "alterId": 4,
                "security": "auto"
              }
            ]
          }
        ]
      }
    }
    

    注意配置相应的 inboundsrouting

事实上,支持套 CDN 的工具有除了 V2Ray 之外还有 GoFlyway。关于使用 GoFlyway 套 CDN 的具体步骤可参见 GoFlyway 进阶教程:免费域名+免费CDN+HTTP伪装=被墙的IP继续做代理 | 逗比根据地IP被墙怎么办?利用Goflyway+CDN救活你的被墙IP! - flyzy小站

Vmess + WS + TLS + CDN

Vmess + WS + TLS + CDN 被称为目前科学上网最安全的手段。虽然其原理复杂,但实现方法非常简单

简介

该方案与上一个方案的区别在于新增了 TLS,因此我们需要先了解 TLS 是什么

TLS

传输层安全性协议(英语:Transport Layer Security,缩写:TLS)及其前身安全套接层(英语:Secure Sockets Layer,缩写:SSL)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。网景公司(Netscape)在1994年推出首版网页浏览器-网景导航者时,推出HTTPS协议,以SSL进行加密,这是SSL的起源。IETFSSL进行标准化,1999年公布第一版TLS标准文件。随后又公布RFC 5246 (2008年8月)与 RFC 6176 (2011年3月)。在浏览器、电子邮件、即时通信、VoIP、网络传真等应用程序中,广泛支持这个协议。主要的网站,如Google、Facebook等也以这个协议来创建安全连线,发送数据。当前已成为互联网上保密通信的工业标准。

SSL包含记录层(Record Layer)和传输层,记录层协议确定传输层数据的封装格式。传输层安全协议使用X.509认证,之后利用非对称加密演算来对通信方做身份认证,之后交换对称密钥作为会谈密钥(Session key)。这个会谈密钥是用来将通信两方交换的数据做加密,保证两个应用间通信的保密性和可靠性,使客户与服务器应用之间的通信不被攻击者窃听。

——引用自传输层安全性协议 - 维基百科,自由的百科全书

具体步骤

这里所谓的具体步骤是在前述的 V2Ray + WS + CDN 的基础上进行的,即假设你已经有了一个二级域名,并使用了一个 CDN

下面给出步骤:

  1. 使用 Certbot 一键获取证书并配置服务器端。

    进入 Certbot 官网。选择 SoftwareNone of the aboveSystemCentOS/RHEL 7。然后根据它的提示操作即可

    对于其中的第 6 步——Install your certificate,由于我们这里的“webserver”是 v2ray,所以这里修改 v2ray 服务端配置文件为如下内容即可:

    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
    
    {
      "port":443,
      "protocol":"vmess",
      "settings":{
        "clients":[{
          "id":"使用自己的 ID",
          "alterId":64
        }]
      },
      "streamSettings": {
        "network":"ws",
        "security": "tls",
        "wsSettings":{
            "path":"/",
            "headers":{}
        },
        "tlsSettings": {
            "serverName": "ja.wsxq2.top",
            "certificates": [{
                "certificateFile": "/etc/letsencrypt/live/ja.wsxq2.top/fullchain.pem",
                "keyFile": "/etc/letsencrypt/live/ja.wsxq2.top/privkey.pem"
            }]
        }
      }
    }
    
  2. 配置客户端。配置文件样例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    {
      "protocol": "vmess",
      "tag": "out_vmess_ws_tls_ja",
      "settings": {
        "vnext": [{
            "address": "ja.wsxq2.top",
            "port": 443,
            "users": [{
                "id": "使用自己的 ID",
                "alterId": 4,
                "security": "auto"
              }]
          }]
       }
    }
    

题外话:我是怎么找到上述获取 TLS 证书的方法的:阅读 V2Ray 官方文档 -> 在 以及广告 · Project V 官方网站 处点击 Let’s Encrypt -> 点击 Getting Started -> 点击 Certbot。选择 SoftwareNone of the aboveSystemCentOS/RHEL 7。根据提示操作即可

Vmess + WS + TLS + CDN + Web

这里的 Web 是指使用 Web 服务(如 Apache 等)反向代理 V2ray

上一个方案(Vmess + WS + TLS + CDN)存在一个问题,就是当你用浏览器直接访问你的 VPS 的 443 端口时,会显示400 Bad Request,在 GFW 看来,这多少有些可疑(一个无法访问的页面,却有着巨大的流量),并且,如果它推算到这可能是一个 Vmess + WS + TLS + CDN 的科学上网方案,那么它会各种试探,这些试探一方面给你的 VPS 性能造成影响,一方面增加被发现的风险(给 GFW 提供分析素材)。因此,将它伪装成一个正常的 Web 网站或许更加安全,这应该才是网上广为流传的“最安全的科学上网方式”

简介

这里我们会用到反向代理,因此我们需要简单了解一下反向代理是什么

反向代理

反向代理在电脑网络中是代理服务器的一种。服务器根据客户端的请求,从其关系的一组或多组后端服务器(如 Web 服务器)上获取资源,然后再将这些资源返回给客户端,客户端只会得知反向代理的 IP 地址,而不知道在代理服务器后面的服务器集群的存在[1]。

与前向代理不同,前向代理作为客户端的代理,将从互联网上获取的资源返回给一个或多个的客户端,服务端(如 Web 服务器)只知道代理的 IP 地址而不知道客户端的 IP 地址;而反向代理是作为服务器端(如 Web 服务器)的代理使用,而不是客户端。客户端借由前向代理可以间接访问很多不同互联网服务器(集群)的资源,而反向代理是供很多客户端都通过它间接访问不同后端服务器上的资源,而不需要知道这些后端服务器的存在,而以为所有资源都来自于这个反向代理服务器。

反向代理在现时的互联网中并不少见,而另一些例子,像是CDNSNI代理等,是反向代理结合 DNS 的一类延伸应用。

——引用自反向代理 - 维基百科,自由的百科全书

反向代理在本方案中的应用如下:

VPS 的 443 端口搭建一个 HTTPS Web 服务器,然后构建一个“像模像样”的网站以混淆视听。当访问特定路径时(比如/awesomepath),将请求转发给 v2ray 处理,v2ray 作为一个在特定端口(如127.0.0.1:12345)监听的Vmess + WS服务,接收到请求后再向实际服务器(比如https://google.com)发起请求,得到响应后将响应转发回 VPS 上的 Web 服务器,VPS 上的 Web 服务器再将响应转发回 v2ray 客户端。外界只能感知到 Web 服务的存在,而感知不到在 Web 后面的 v2ray 的存在。

具体步骤

同样地,这里所谓的具体步骤是在前述的 V2Ray + WS + TLS + CDN 的基础上进行的,即假设你已经有了一个二级域名,并使用了一个 CDN,且配置了 TLS 证书。

具体步骤如下(以 CentOS 7 为例):

  1. 关掉 CDN 以便于测试。

    Cloudflare 控制面板DNS 处将你的 VPS 的域名设置如下:

    1
    
    A www 93.179.128.98 Auto Direct
    
  2. 修改 V2ray 服务配置。

    将监听端口改为你喜欢的端口(如 12345);删除 TLS 相关的配置(这里只需要用到Vmess + WSTLS 交给前面的 Web 服务)。即改成类似于这样的配置文件

  3. 重启正在运行的 V2ray 服务。

    使用如下命令即可:

    1
    
    systemctl restart v2ray
    
  4. 安装并启用你喜欢的 Web 服务,测试。

    提供 Web 服务的软件有很多,如 apache、ngnix、lighttpd、caddy 等。下面以 lighttpd(一个轻量的 Web 服务)为例

    1
    2
    3
    
    yum install lighttpd
    systemctl start lighttpd
    systemctl enable lighttpd
    

    测试方法很简单,访问你的 Web 服务器(假设你的 VPS 使用的域名是www.example.com),看是否出现默认页面:http://www.example.com

  5. 放置你的 Web 内容,测试。

    上传你的网站内容,这可以是你的个人博客,也可以是爬的其它站点,看起来还不错就行

    测试:http://www.example.com

  6. 为提供 Web 服务的软件配置证书,测试。

    修改提供 Web 服务的软件(这里是 lighttpd )的配置文件中的SSL 配置部分即可:

    1
    2
    3
    4
    5
    6
    7
    
    #SSL配置,依赖 mod_ssl
    $SERVER["socket"] == "0.0.0.0:443" {
         ssl.engine                  = "enable"
         ssl.privkey                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/privkey.pem"
         ssl.pemfile                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/cert.pem"
         ssl.ca-file                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/chain.pem"
    }
    

    完整配置可参考后面的 参考配置文件-Web-lighttpd

    测试:https://www.example.com

  7. 配置反向代理到 V2ray,测试。

    修改提供 Web 服务的软件(这里是 lighttpd )的配置文件中的反向代理部分即可:

    1
    2
    3
    4
    5
    
    #WS反向代理,依赖 mod_proxy
    $HTTP["url"] =~ "^/awesomepath" {
        proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "12345" ) ) )
            proxy.header = ( "upgrade" => "enable" )
    }
    

    完整配置可参考后面的 参考配置文件-Web-lighttpd

    测试:https://www.example.com/awesomepath

  8. 修改客户端配置文件,测试。

    修改 V2ray 客户端配置文件如下:参见后面的 参考配置文件-V2ray-client

    测试:参见 测试

  9. 套上 CDN

    Cloudflare 控制面板DNS 处将你的 VPS 的域名设置如下:

    1
    
    A www 93.179.128.98 Auto Proxied
    

    如果你发现你的 IP 突然又被解封了,那么你可以尝试关掉 CDN,只需采用上述步骤即可,其它配置无需变动,非常方便(Trojan 不支持套 CDN

  10. 完成

另请参见下列文章:

参考配置文件

v2ray

server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
         {
            "port": 12345,
            "protocol": "vmess",
            "host": "sub.wsxq2.xyz",
            "ps":"搬瓦工美国02 - Vmess_WS_TLS - V2ray",
            "settings": {
                "clients": [
                {
                    "id": "0f9cf274-705c-46d3-ad7a-823ec8747220",
                    "level": 1,
                    "alterId": 64
                }
                ]
            },
            "streamSettings": {
                "network": "ws",
                "wsSettings": {
                    "path": "/awesomepath"
                }
            },
            "listen": "127.0.0.1"
        }

上面的配置是放在inbounds中的。

client
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
    {
      "protocol": "vmess",
      "tag": "out_ja_vmess_ws_tls",
      "settings": {
        "vnext": [
          {
            "address": "gj.wsxq2.xyz",
            "port": 443,
            "users": [
              {
                "id": "8caa9650-2387-4d0e-bff9-8cb121488a6f",
                "alterId": 4,
                "security": "auto"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "wsSettings": {
          "path": "/awesomepath",
          "headers": {}
        },
        "network": "ws",
        "security": "tls"
      }
    },

上面的配置是放在outbounds中的。

Web

apache

本部分以 CentOS 7 上的 httpd 2.4.6(CentOS 上的 apache 软件包叫做 httpd) 为例

conf/httpd.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
<VirtualHost _default_:443>
ServerName gj.wsxq2.xyz

RewriteEngine On
RewriteCond %{REQUEST_URI} =/awesomepath [NC]
RewriteRule /awesomepath           ws://127.0.0.1:12345/awesomepath [P,L]

ProxyPassReverse /awesomepath ws://127.0.0.1:12345/awesomepath

ProxyAddHeaders Off
ProxyPreserveHost On

</VirtualHost>
conf.d/ssl.conf
1
2
3
4
5
<VirtualHost _default_:443>
SSLEngine on
SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
SSLCertificateFile "/etc/letsencrypt/live/gj.wsxq2.xyz/cert.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/gj.wsxq2.xyz/privkey.pem"
lighttpd

本部分以 CentOS 7 上的 lighttpd/1.4.54 为例

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
#SSL配置,依赖 mod_ssl
$SERVER["socket"] == "0.0.0.0:443" {
     ssl.engine                  = "enable"
     ssl.privkey                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/privkey.pem"
     ssl.pemfile                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/cert.pem"
     ssl.ca-file                 = "/etc/letsencrypt/live/sub.wsxq2.xyz/chain.pem"
}

#将 HTTP 访问重定向为 HTTPS 访问,依赖 mod_redirect
$HTTP["scheme"] == "http" {
    # capture vhost name with regex conditiona -> %0 in redirect pattern
    # must be the most inner block to the redirect rule
    $HTTP["host"] =~ ".*" {
        url.redirect = (".*" => "https://%0$0")
    }
}

#拒绝IP及其它域名访问(来自 https://stackoverflow.com/a/40818494), 依赖 mod_access
$HTTP["host"] != "sub.wsxq2.xyz" {
    url.access-deny = ("")
}


#WS反向代理,依赖 mod_proxy
$HTTP["url"] =~ "^/awesomepath" {
    proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "12345" ) ) )
        proxy.header = ( "upgrade" => "enable" )
}

通过已经可以科学上网的电脑实现科学上网

也就是说,如果你有一台设备通过上述的方法(SSH/SS/SSR/V2Ray/V2Ray+WS+CDN/V2Ray+WS+TLS+CDN)之一实现了科学上网,那么你就可以借助那台设备轻松地让其它和那台设备属于同一局域网的设备实现科学上网。比如你的实体机(如 Windows)实现了科学上网,那么对于你的 kali 虚拟机你就没必要想尽各种办法让它与你的实体机进行类似的配置以实现科学上网,你只需让虚拟机和 Windows 主机处于同一局域网下即可(对于 Virtual Box 可使用仅主机网络)。

前提条件

  • 已经实现科学上网的主机使用了 SSH/SS/SSR/V2Ray/V2Ray+CDN/V2Ray_WS+TLS+CDN 这几个方法之一。它们的共同点在于都有一个本地代理,且对于这个本地代理,可以将监听地址从127.0.0.1 1080改为0.0.0.0 1080
  • 和可以科学上网的主机处于同一局域网

基本原理

因为默认情况下,出于安全性考虑,我们通常将本地代理中的监听地址设为127.0.0.1 1080。而事实上,在局域网内是相对安全的,如果想让别人能够访问你的本地代理,可以将其改为0.0.0.0 1080

其中 127.0.0.1(即网卡 loopback 的 IP 地址) 是本地环回地址,同一局域网内的其它主机无法访问,只有它自己能访问;0.0.0.0 则不然,它用于表示本机上的任意网卡(除了 loopback)。如果需要让同一局域网内的其它主机访问,必需指定具体的网卡的 IP 地址或者使用 0.0.0.0(这个 IP 用于表示本机上的任意网卡)。

例如,你有两个网卡,一个是用于连接 Virtual Box 中的虚拟机的仅主机网络IP 地址为192.168.56.100),另一个是用于上网的 WIFI(IP 地址为192.168.2.102),出于安全性考虑,你只打算和虚拟机共享本地代理,不打算让连接到同一 WIFI 中的主机共享本地代理,那么你可以让本地代理的监听地址为192.168.56.100 1080

如果想让任意网卡共享本地代理,即可配置为0.0.0.0 1080

具体方法

实验环境:主机 Windows10 (已实现科学上网),虚拟机 Kali Linux(需要实现科学上网),对于虚拟机 Kali,我使用了两个网卡,网络地址转换仅主机网络,前者保证能连上 Internet,后者保证让 主机和虚拟机处于同一局域网(网段为 192.168.56.0/24)

实现步骤(以 SSR 为例):

  1. 配置主机的 SSR 客户端,使其允许来自局域网的连接。右键任务栏最右边的小飞机图标->点击选项设置->勾选来自局域网的连接

    此时,在 Powershell 或 CMD 中输入netstat -ano | findstr "LISTENING"即可看到本地代理的监听地址从127.0.0.1 1080变为了0.0.0.0 1080

  2. 在虚拟机中,配置 FireFox 浏览器中的网络代理或系统代理,选择手动代理,在所有代理中填入主机的 IP 地址和其默认的端口(我的是192.168.56.1001080
  3. 完成

测试

  • TODO: 本部分需要完善 <2019-07-07>

最基本的测试是在配置好后,打开你的浏览器,在地址栏输入,如果访问成功,则恭喜你!

当然,通常不会一次性成功。那么失败时我们该从何下手呢?

让我们从通用测试方法开始

通用测试方法

  • ping。ping 命令可以用于检测本机和目的主机是否相通。当然,防火墙可能阻止 ping 命令的成功,即 ping 不通不代表连不上(但通常不会出现这种情况)。同时 ping 得通也不代表连得上(例如 TCP 阻断,此时需要更换端口或 IP)。ping 得通说明你的 IP 没被封
  • tracert(Linux 中为traceroute)。用于追踪 IP。可以用来追踪你的 VPSIP 地址,从而得出途径的网络节点。除了使用该工具达到这个目的,还可以使用在线工具达到同样目的,且发出tracert命令的主机为各地的主机
  • nc。作为网络调试中的瑞士军刀,其功能非常强大。初始版本过旧,建议使用衍生版本,如ncat(Nmap 官方出品)。它最基本的一个用法是测试目标端口是否打开或是否连得上
  • telnettelnet具有基本的 TCP 连接的能力,可用于测试目标端口是否打开或是否连得上
  • 抓包。但凡涉及到网络,抓包总是不会错的。推荐的抓包工具为 Wiresharktcpdump。前者适用于有图形界面的,后者适用于无图形界面的(即 Shell)。再简单点地说,tcpdump 用于在服务器(例如 CentOS )上抓包,Wireshark 用于在带图形界面的客户端(例如 Windows)上抓包。

常用工具

本地工具

  • arp(二层——数据链路层):ARP
  • ifconfig, ip, route(三层——网络层):MAC, IPv4, IPv6
  • ping, traceroute(三层——网络层):ICMP
  • netstat, ss(四层——传输层):TCP, UDP
  • telnet, nc(四层——传输层):TCP
  • nslookup, dig(五层——应用层):DNS
  • dhcpclient(五层——应用层):DHCP
  • wget, lynx: HTTP, HTTPS, FTP
  • curl:FILE, FTP, FTPS, HTTP, HTTPS, IMAP, IMAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET, TFTP
  • tcpdump: all
  • whois: ?

其中lynx是个终端下使用的轻量浏览器,更多轻量浏览器请参见 Comparison of lightweight web browsers - Wikipedia

更多 Linux 下的网络工具请参见: Linux常用网络工具总结 - int32bit的博客 | int32bit Blog

在线工具

科学上网问题测试思路

可以按如下顺序正向进行,也可反向进行:

  1. 确保你的服务器可以访问谷歌,使用如下命令:
    1
    
    curl -s -i -4 -m 10 www.google.com | less
    

    简要解释下:curl是一个强大的用于在服务器和客户端间传输数据的工具。上述命令使用的是其最常用的一个能力,获取 Web 网页。其中:

    • -s参数是为了防止出现进度条,影响阅读;
    • -i参数是为了让其显示响应头(Response header);
    • -m 10表示最多只等 10s,否则可能等很长时间才返回失败信息;
    • www.google.com参数用于指明从http://www.google.com获取数据;
    • |是管道,用于将curl命令的输入重定向为less命令的输入;
    • less命令的作用是分页显示输入的内容(通常用于原文过长,一个屏幕显示不全的情况)。

    如果成功,其输出应当如下:

    1
    2
    3
    4
    5
    6
    7
    8
    
    HTTP/1.1 200 OK
    Date: Thu, 04 Jul 2019 03:17:26 GMT
    Expires: -1
    Cache-Control: private, max-age=0
    Content-Type: text/html; charset=ISO-8859-1
    P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
    Server: gws
    ......
    
  2. 确保你可以连接到你的服务器(如果 IP 已经被封(即使用了 V2Ray + CDN 等方案)这点不做要求)。先使用 ping 看下 IP 是否被封(注意使用你的服务器的 IP 替换下面的演示 IP):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    PS C:\Users\wsxq2> ping 104.27.157.73
    Pinging 104.27.157.73 with 32 bytes of data:
    Reply from 104.27.157.73: bytes=32 time=185ms TTL=52
    Reply from 104.27.157.73: bytes=32 time=186ms TTL=52
    Reply from 104.27.157.73: bytes=32 time=186ms TTL=52
    Reply from 104.27.157.73: bytes=32 time=187ms TTL=52
    
    Ping statistics for 104.27.157.73:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 185ms, Maximum = 187ms, Average = 186ms
    

    上面的是 ping 成功的例子(用的命令行是 Windows 10 中 Powershell),说明 IP 没被封。如果 ping 失败,则很有可能 IP 被封了。下面测试 TCP 连接是否正常(尝试使用 SSH 连接到你的服务器,注意替换master):

    1
    2
    3
    4
    5
    6
    
    PS C:\Users\wsxq2> ssh master
    The authenticity of host 'master (192.168.56.11)' can't be established.
    ECDSA key fingerprint is SHA256:0Y6BmNB1vsQiK2RSf9Ux9qcPlESud8C3UYIvtMZeKGs.
    Are you sure you want to continue connecting (yes/no)? no
    Host key verification failed.
    PS C:\Users\wsxq2>
    

    如果出现上面的提示(The authenticity of host...),则说明可以连接。如果出现如下提示(注意替换 IP):

    1
    2
    3
    
    PS C:\Users\wsxq2> ssh 192.168.56.13
    ssh: connect to host 192.168.56.13 port 22: Connection timed out
    PS C:\Users\wsxq2>
    

    则说明连接不上

    除了使用 ssh 本身测试 SSH 服务是否可用外,还可以使用 telnet:

    1
    
    PS C:\Users\wsxq2> telnet master 22
    

    如果 Powershell 界面刷新,并显示如下信息:

    1
    
    SSH-2.0-OpenSSH_7.4
    

    则说明连得上,否则说明连不上

  3. 测试你和你的服务器上的用于科学上网的端口是否可以连通。这个测试的前提是上面的 SSH 连接测试成功了

    先打开已经安装在 Windows 上的 Wireshark,选择你和服务器之间连接使用的网卡进行数据包嗅探。然后使用 Windows 自带的 telnet 连接到你的服务器上的用于科学上网的端口(注意替换 IPmaster)和端口(1234)):

    1
    
    PS C:\Users\wsxq2> telnet master 1234
    

    在 Wireshark 中查看是否抓到如下数据包(即查看 TCP 三次握手是否成功):

    1
    2
    3
    
    1	0.000000	192.168.56.100	192.168.56.11	TCP	66	8754 → 1234 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
    2	0.000306	192.168.56.11	192.168.56.100	TCP	66	1234 → 8754 [SYN, ACK] Seq=0 Ack=1 Win=29200 Len=0 MSS=1460 SACK_PERM=1 WS=128
    3	0.000369	192.168.56.100	192.168.56.11	TCP	54	8754 → 1234 [ACK] Seq=1 Ack=1 Win=525568 Len=0
    

    如果失败,说明你和你的服务器上的用于科学上网的端口无法连接。可能是因为端口没有开启、TCP 被阻断之类的原因导致的。对于前者,可在服务器上使用如下命令查看端口是否开启:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    root@wsxq21:~# ss -ntl
    State      Recv-Q Send-Q               Local Address:Port                              Peer Address:Port
    LISTEN     0      50                       127.0.0.1:3306                                         *:*
    LISTEN     0      128                              *:26635                                        *:*
    LISTEN     0      100                      127.0.0.1:25                                           *:*
    LISTEN     0      128                              *:12635                                        *:*
    LISTEN     0      128                             :::26635                                       :::*
    LISTEN     0      128                             :::80                                          :::*
    LISTEN     0      128                             :::8080                                        :::*
    LISTEN     0      128                             :::11635                                       :::*
    LISTEN     0      100                            ::1:25                                          :::*
    root@wsxq21:~#
    

    对于 TCP 阻断,可更换一个端口试试

  4. 测试你的客户端软件是否开启。使用如下命令:
    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
    
    PS C:\Users\wsxq2> netstat -ano|findstr "LISTENING"
      TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       576
      TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
      TCP    0.0.0.0:1080           0.0.0.0:0              LISTENING       11328
      TCP    0.0.0.0:1536           0.0.0.0:0              LISTENING       684
      TCP    0.0.0.0:1537           0.0.0.0:0              LISTENING       1484
      TCP    0.0.0.0:1538           0.0.0.0:0              LISTENING       1368
      TCP    0.0.0.0:1539           0.0.0.0:0              LISTENING       2928
      TCP    0.0.0.0:1545           0.0.0.0:0              LISTENING       828
      TCP    0.0.0.0:1547           0.0.0.0:0              LISTENING       840
      TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       5416
      TCP    0.0.0.0:5938           0.0.0.0:0              LISTENING       3708
      TCP    0.0.0.0:7680           0.0.0.0:0              LISTENING       13036
      TCP    0.0.0.0:23443          0.0.0.0:0              LISTENING       11196
      TCP    10.177.15.93:139       0.0.0.0:0              LISTENING       4
      TCP    127.0.0.1:1081         0.0.0.0:0              LISTENING       11528
      TCP    127.0.0.1:1562         0.0.0.0:0              LISTENING       9864
      TCP    127.0.0.1:4300         0.0.0.0:0              LISTENING       10268
      TCP    127.0.0.1:4301         0.0.0.0:0              LISTENING       10268
      TCP    127.0.0.1:5939         0.0.0.0:0              LISTENING       3708
      TCP    127.0.0.1:10000        0.0.0.0:0              LISTENING       3448
      TCP    127.0.0.1:28317        0.0.0.0:0              LISTENING       3696
      TCP    127.0.0.1:41830        0.0.0.0:0              LISTENING       16080
      TCP    127.0.0.1:54530        0.0.0.0:0              LISTENING       9072
      TCP    127.0.0.1:62783        0.0.0.0:0              LISTENING       14884
      TCP    127.0.0.1:65000        0.0.0.0:0              LISTENING       3220
      TCP    127.0.0.1:65001        0.0.0.0:0              LISTENING       3220
      TCP    169.254.64.217:139     0.0.0.0:0              LISTENING       4
      TCP    192.168.56.100:139     0.0.0.0:0              LISTENING       4
      TCP    [::]:135               [::]:0                 LISTENING       576
      TCP    [::]:445               [::]:0                 LISTENING       4
      TCP    [::]:1080              [::]:0                 LISTENING       11328
      TCP    [::]:1536              [::]:0                 LISTENING       684
      TCP    [::]:1537              [::]:0                 LISTENING       1484
      TCP    [::]:1538              [::]:0                 LISTENING       1368
      TCP    [::]:1539              [::]:0                 LISTENING       2928
      TCP    [::]:1545              [::]:0                 LISTENING       828
      TCP    [::]:1547              [::]:0                 LISTENING       840
      TCP    [::]:5938              [::]:0                 LISTENING       3708
      TCP    [::]:7680              [::]:0                 LISTENING       13036
      TCP    [::1]:1546             [::]:0                 LISTENING       2488
    PS C:\Users\wsxq2>
    

    在其中找到你设置的本地端口号(SS Local),通常为 1080(可以直接使用netstat -ano|findstr ":1080"命令)

  5. 检查你本地代理配置是否正确。一个简单可靠的方法是使用 Chrome + SwitchyOmega,新建一个类型为代理服务器情景模式代理协议设置为 socks5,代理服务器设置为本地代理的 IP (通常为 127.0.0.1),代理端口设置为本地代理配置的端口(通常为 1080)。

如果上述测试均成功,那可能是你的配置文件有问题,包括服务器和客户端,请仔细检查。

一些尝试

分析 SSR 科学上网失败原因

这个问题发生在我才接触科学上网不久后,那时我一直用的 SSR(因为有一次 SS 抽风了我就认为 SS 已经不能用了)。在 2019-06-01 左右的某一天,SSR 也抽风了。经过抓包分析,最后发现是因为三次握手失败。更加准确地说,是因为服务端能收到客户端的数据包,但是客户端收不到服务端的响应包,即客户端反复地重发 SYN,但是总是收不到回复。

此外,ping 和 ssh 均失败、使用手机依然失败、重启客户端和服务器无效、检查服务器开放端口正常、检查服务器防火墙状态正常、使用其它 VPS 能连上、等了一个月依然存在上述现象,这些现象足以证明是 IP 被封了

由于服务端能收到客户端的数据包,所以我当时有个大胆而简单的想法,即修改一下服务端 SSR 软件,在收到客户端请求后返回响应数据时将其源 IP 修改为其它 IP 地址(因为 GFW 封的 IP 是源 IP 为国外的 IP的数据包),只要再修改一下客户端 SSR 软件,让其能还原会话就可以成功使用。

如今想来,这个解决方法事实上还是挺复杂的。因为每次从服务端发来的包都需要修改源 IP ,而标识一个会话的关键因素就是双方IP,双方端口,使用的协议(五元组)。故而修改一方 IP 后还能还原会话是一大挑战。而且 GFW 想破解该方法不要太简单,它直接封了目的 IP 为你的 VPS IP 的数据包就行

分析 SS 科学上网失败原因

这是由于最近(2019-12-05) SS 虽然可以使用,但是经常间歇性抽风。在抽风时,我试图通过抓包分析问题所在。易知,问题主要出在客户端和服务器端之间的流量上,因此需要抓取两端的流量包以进行综合分析。

在客户端上抓取以太网接口(或 WIFI 接口)的流量即可。然后使用如下显示过滤器(这里及后面用的均是 Wireshark):

1
tcp.port==16834 and tcp.flags.syn==1 and tcp.flags.ack==0

其中注意将16834改为你自己的 SS 服务器端口。

与此同时,在服务器上抓取相应的网卡(也叫接口)流量(通常是eth0),但是由于服务器端通常没有图形界面,所以无法直接使用 Wireshark。但是,可以使用 Wireshark 的 sshdump 模块,直接在你的客户端上抓取服务器上的流量(这个功能超级强大有木有)。它需要在服务端上安装 tcpdump,然后客户端上使用 SSH 连接并传输流量信息。具体操作步骤可自行谷歌

在客户端上,选定一条记录,按Ctrl+Shift+Alt+T以 Follow TCP Stream;在服务端上,选定对应的记录(可根据客户端的端口来找到对应的记录),按Ctrl+Shift+Alt+T以 Follow TCP Stream。将两端显示的包记录分别保存为notebook_ssserver.pcapngnotebook_ssclient.pcapng,以待后续对比分析

通过对比分析得到的两个包,最终发现问题出在第二轮数据交换(客户端发送数据,服务端响应算一轮)中,即在客户端三次握手成功并经历了一次数据交换后,在客户端再次向服务端发送数据时,出现了服务端接收失败的现象,服务端因为没有接收到数据,所以在等待了 10 秒后发送了一个 FIN 包企图结束此次会话,但是客户端不死心,反复重发,最后依然没有得到希望的回复,只能发送 FIN 和 RST 结束会话

(突然感觉客户端和服务器是两个相亲相爱的人,但是 GFW 拆散了它们,它让它们产生误会,产生隔阂,导致客户端郁郁而终的悲剧。妈蛋,单身久了抓个包都觉得眉清目秀。:sob:

在此我有点好奇,为何在第二次客户端请求时会被 GFW 拦截?难道是因为该数据包有什么显而易见的特征被 GFW 检测到了?怀着疑问,我试图将该数据包解密,先看看数据包的明文内容再说。

因为 openssl 有巨多的加解密算法,于是我开始研究如何使用 openssl 解密一段密文。

最终,由于我的 SS 使用的是 aes-128-gcm 加密方式,但是 openssl 不支持该加密方式的加解密,因此只能不了了之

国内服务器上搭建 v2ray 作为中转

  • 时间:2019-12-05 左右

这个尝试源于我所在的网络环境比较糟糕,我所在的网络环境是 NAT 中的 NAT 中的 NAT……(我也不清楚嵌套了多少层,可以肯定的是至少两层)。因此,如果大家都在使用科学上网,那么被 GFW 检测的概率会大大增加,就可能会出现短暂地封源 IP 的结果。面对这个问题,一个简单的解决方法便是使用国内服务器进行中转。

为了提到效率,可以将客户端到中转服务器间的协议设为 HTTP,即将中转服务器作为一个 HTTP 代理服务器使用。这样一来,客户端的配置会简单很多,简单到不需要安装客户端软件了。

甚至你还可以将一个 PAC 放到你的 HTTP 代理服务器上,这样还能实现自动代理。客户端几乎不用任何配置(只需在网络设置处配置一个 PAC 文件 URL

缺点是性能可能会下降

具体步骤就不赘述了

在执行这个想法的过程中,遇到了一个万万没想到的问题:Chrome 竟然不支持 SOCKS5 的用户l密码认证 2。并且使用 PAC 也达不到想要的结果,即因为 Chrome 不支持 SOCKS5 的用户密码认证,所以在 PAC 文件中包含认证信息也是毫无意义的。不仅如此,Firefox 和 MSIE 也是不支持的 3

用七牛云的 CDN 以提高科学上网的速度

  • 时间:2019-12-05 左右

由于听闻国内 CDN 速度更快(相比于 Cloudflare),于是我试图使用七牛云的 CDN 以提高科学上网的速度,但是由于以下原因最终放弃了:

  1. (最关键)使用七牛云的 CDN 需要域名备案。
  2. 使用 HTTPS 要收费
  3. 不一定能起到加速效果,毕竟 VPS 在国外

进一步阅读

总结

本文花了我整整一个周的时间,且期间没有偷懒,几乎每天除了吃饭睡觉和少有的看小说、看动漫、玩游戏(怎么突然感觉自己还是不够努力 :joy: )的时间都是在写这个博客。如今虽然还有很多内容需要完善,但是我还是打算暂时先放下了。主要是因为太累了 :sob:

由此可见,翻墙是门大学问。的确,在写这个博客的过程中我也学到了不少新知识,尤其对其原理和测试方法更加清晰。其中体会最深的莫过于抓包的作用之大。因此,我得出了如下结论:但凡涉及网络,抓包总是没错的。

另外非常感谢网上的各种教程,为我指明了方向。他们勇于探索、敢于创新、刻苦钻研、无私奉献、崇尚自由的精神让我非常钦佩。

最后引用 SS 作者 clowwindy 的一段话:

维护这个项目到现在大概总共回复过几千个问题,开始慢慢想清楚了一件事,为什么会存在GFW。从这些提问可以看出,大部分人的自理能力都很差,只是等着别人帮他。特别是那些从AppStore下载了App用着公共服务器的人,经常发来一封只有四个字的邮件:“不能用了?”我觉得这是一个社会常识,花一分钟写的问题,不能期待一个毫无交情的陌生人花一个小时耐心地问你版本和操作步骤,模拟出你的环境来帮你分析解决。Windows版加上GFWList功能以来,我反复呼吁给GFWList提交规则,但是一个月过去了竟然一个提交都没有。如果没有人做一点什么,它自己是不会更新的啊,没有人会义务地帮你打理这些。我觉得,政府无限的权力,都是大部分人自己放弃的。假货坑爹,让政府审核。孩子管不好,让政府关网吧。房价太高,让政府去限购。我们的文化实在太独特,创造出了家长式威权政府,GFW正是在这种背景下产生的,一个社会矛盾的终极调和器,最终生活不能自理的你每天做的每一件事情都要给政府审查一遍,以免伤害到其他同样生活不能自理的人。这是一个零和游戏,越和这样的用户打交道,越对未来持悲观态度,觉得GFW可能永远也不会消失,而墙内的这个局域网看起来还似乎生机勃勃的自成一体,真是让人绝望。

——引用自Linux 科学上网指南 | Firmy’s blog

更新记录

这里指的是重大更新记录。

更新时间 版本 耗时 变动
2019-07-07 1.0 7 天 初稿。
2019-08-04 2.0 好几个晚上 + 2 个白天 添加了配置公私钥的部分,极大地完善了代理部分,添加了 SS 服务器配置手动安装方法(shadowsocks-libev),修正了部分错误(包括 SSH 那部分的),移除了PC 连接到 SSR Local这一部分的内容(它被移动到了代理部分)。在前面的多个小节前添加了说明文字
2019-11-29 3.0 一个下午 完善了 V2Ray + WS + CDN 部分和 V2Ray + WS + TLS + CDN 部分
2019-12-05 4.0 一个上午(2小时) 添加了一些尝试部分
2020-06-19 5.0 一个下午(3小时) 添加了一些推荐的“机场”、 VPS 提供商、域名购买站点,添加了“真·最安全的科学上网方式”(Vmess + WS + TLS + CDN + Web),修正了一些链接

链接

下面总结了本文中使用的所有链接:

缩略语

  • ACK: ACKnowledgement
  • API: Application Programming Interface
  • ARM: Advanced RISC Machines
  • ARP: Address Resolution Protocol
  • BT: BitTorrent
  • CDN: Content Delivery Network
  • CMD: CoMmanD
  • CPU: Central Processing Unit
  • CST: China Standard Time
  • DHCP: Dynamic Host Configuration Protocol
  • DNS: Domain Name System
  • DPI: Deep Packet Inspection
  • ECDSA: Elliptic Curve Digital Signature Algorithm
  • FTP: File Transfer Protocol
  • FTPS: File Transfer Protocol over TLS
  • GCP: Google Cloud Platform
  • GFW: Great Firewall
  • GIA: Global Internet Access
  • GMT: Greenwich Mean Time
  • GPL: General Public License
  • GUI: Graphical User Interface
  • HTTP: Hypertext Transfer Protocol
  • HTTPS: HTTP Secure
  • ICMP: Internet Control Message Protocol
  • ICP: Internet Content Provider
  • ID: Identifier
  • IDL: Interface Definition Language
  • IEEE: Institute of Electrical and Electronics Engineers
  • IETF: Internet Engineering Task Force
  • IHMSC: International Conference on Intelligent Human-Machine Systems and Cybernetics
  • IMAP: Internet Message Access Protocol
  • IMAPS: IMAP Secure
  • IP: Internet Protocol
  • ISO: International Organization for Standardization
  • ISP: Internet Service Provider
  • JSON: JavaScript Object Notation
  • KB: Kilobyte
  • KCP: A Fast and Reliable ARQ Protocol
  • MAC: Media Access Control
  • MB: Megabyte
  • MIPS: Microprocessor without Interlocked Pipeline Stages
  • MIT: Massachusetts Institute of Technology
  • MSS: Maximum Segment Size
  • NG: Next Generation
  • OS: Operating System
  • OSI: Open Systems Interconnection
  • OSX: macOS
  • PAC: Proxy auto-config
  • PC: Personal Computer
  • PID: Process ID
  • POSIX: Portable Operating System Interface, formerly IEEE-IX
  • PS: PowerShell
  • PTR: PoinTeR
  • RFC: Request For Comments
  • RTMP: Real-Time Messaging Protocol
  • RTSP: Real Time Streaming Protocol
  • SCP: Secure Copy
  • SFTP: SSH File Transfer Protocol
  • SMTP: Simple Mail Transfer Protocol
  • SMTPS: SMTP over TLS
  • SNI: Server Name Indication
  • SOCKS: SOCKetS
  • SS: shadowsocks
  • SSH: Secure Shell
  • SSL: Secure Socket Layer
  • SSR: shadowsocksr
  • SSRR: shadowsocksrr
  • TCP: Transmission Control Protocol
  • TFTP: Trivial File Transfer Protocol
  • TLS: Transport Layer Security
  • TTL: Time To Live
  • TTY: Teletype
  • UDP: User Datagram Protocol
  • URI: Uniform Resource Identifier
  • URL: Uniform Resource Locator
  • VM: Virtual Machine
  • VPN: Virtual Private Network
  • VPS: Virtual Private Server
  • WPAD: Web Proxy Autodiscovery Protocol
  • WS: WebSocket
  • WWW: World Wide Web

引用

  1. https://github.com/v2ray/v2ray-core/issues/1769 

  2. https://bugs.chromium.org/p/chromium/issues/detail?id=256785 

  3. https://stackoverflow.com/a/1983813