序言
好吧! 也许是时候公布新功能了. 关心这个项目的人, 绝大部分懂中文, 咱也就不装了, 不飙英文了, 累.
因为俺憋了个大招.
GFW 不是老在搞 深度包检测(Deep packet inspection, DPI) 吗? SS/SSR 与 GFW 在这一点上斗了好多年, 我加点伪装, 你加大侦测力度, 我再加点混淆, 你再加点AI识别算法, 此消彼长, 犬牙交错, 无穷无尽. 看得人厌倦透顶.
咱不装了, 咱来真的, 我们给 GFW 带来全新礼物, 给 SSR 添加了 over TLS 特性, 用真的 HTTPS 数据包翻墙! 简称 SSRoT. 您 GFW 慢慢算去!
补记: 时维2019年10月2日, 经过空前严酷的 国殇 日前后的 GFW 封锁, 我本人没发现 SSRoT 运行状态有任何异常, 此前也只有一例电邮报告被墙, 具体原因估计是 GFW 针对某一网段的无差别封杀. 此外再无任何报告. 这证明 SSRoT 的越墙能力是毋庸置疑的.
补记2: 2020年2月1日, 新冠瘟疫 横行, 墙再次加高, SSRoT 依然从容穿越 GFW 向兲朝猪圈传递未经审查的自由资讯.
在正式开始前, 介绍一个概念: 反向代理.
反向代理
反向代理(Reverse Proxy)是指, 服务器 根据 客户端 的请求,从其关联的一组或多组后端服务器(如 Web 服务器)上获取资源,然后再将这些资源返回给 客户端,客户端 只会得知 反向代理 服务器的 IP 地址,而不知道在 代理服务器 后面的 服务器 集群的存在。
与前向代理不同,前向代理作为 客户端 的代理,将从互联网上获取的资源返回给一个或多个的 客户端,服务端(如Web服务器)只知道代理的 IP 地址而不知道 客户端 的 IP 地址;而 反向代理 是作为 服务端(如Web服务器)的代理使用,而不是客户端。客户端 借由 前向代理 可以间接访问很多不同 互联网服务器(集群)的资源,而 反向代理 是供很多 客户端 都通过它间接访问不同 后端服务器 上的资源,而不需要知道这些 后端服务器 的存在,而以为所有资源都来自于这个 反向代理 服务器。
举个例子,某用户访问 http://www.example.com/readme ,但是 www.example.com 上并不存在 readme 页面,它是偷偷从另外一台服务器上取回来,然后作为自己的内容返回给用户。但是用户并不知情这个过程。对用户来说,就像是直接从 www.example.com 获取 readme 页面一样。这里所提到的 www.example.com 这个域名对应的 web 服务器 就设置了 反向代理 功能。
反向代理 在现时的互联网中应用非常广泛。
SSR over TLS 原理
SSR over TLS (简称 SSRoT) 就是直接利用了 反向代理, 在现代 web 服务器( 比如 nginx, caddy, apache 等)上, 添加一条设置, 当 SSR 客户端向 web 服务器 以特定 URL 请求资源时, web 服务器 将这个请求直接转发到 SSR 服务器, SSR 服务器再将这条请求以约定算法解包后发送到 目标网站. 见下图.
我们的目的是为了避开 GFW 的审查,当然不能明晃晃地使用 HTTP 明文传输,必须使用 HTTPS 协议进行加密通讯, 我们此前的努力就是伪装成正规的 HTTPS 协议等, 这次我们不装了, 就使用堂堂正正的 HTTPS 协议, 与真正的带域名 和 网站数字安全证书的 web 服务器网站通讯, 这样, 你 GFW 没办法了吧?
当然, 我党 也不是完全没办法, 有几个:
- 宣布 HTTPS 协议为反党反社会主义的反动协议, 必须坚决予以取缔. —— 你认为会有这么一天吗? 我认为不会, 这完全不具备可操作性. 比较有意思的是, 我党的 政府网站 以及一众徒子徒孙们, 全部是 HTTP, 而不是 HTTPS. 亦可赛艇.
- 向 朝鲜 🇰🇵 看齐, 偌大中国只有几十数百个国外 IP 可以访问, 其它一概封杀. 那, 我也没办法了, 还翻什么墙啊? 我们 —— 被剥夺了基本 通讯自由 以至于上个破网都是犯罪的十几亿猪民 —— 是不是有比宅家里猥琐地偷摸翻墙更重要的事要做?拥有这数百 IP 管理权的 猪倌 们, 别犹豫, 赶紧把 SSRoT 部署起来, 这是你们一夜暴富的最后机会.
- 加强 GFW 的识别算法, 当然努力的方向不再是 深度包检测, 而是 域名 字串特征 和 网站 内容判别了, 我党 甚至可能引入 社会工程学 手段进行人肉搜索来确定某人是否在翻墙. —— 这问题不属于本软件所能解决的范畴了.比如域名里出现了 FuckCCP 字样, GFW 肯定会判定为应该封锁的网站. 又如, 如果你网站只是简单的一个示例网页, 却每天有大量数据交换, 那就可以判定为翻墙站点了.
因此, 稳妥的做法是, 为你的翻墙站点, 注册一个 爱党爱国 的域名, 然后在这个网站上放置不算太少的 颂扬 我党 的文字, 图片, 视频 等, 或者干脆充斥着 娱乐至死 的游戏评测视频以及 吃喝玩乐 各种资讯, 等等. 这就伪装得差不多了, GFW 即使启用超强 AI 引擎运算, 应该也判别不出你到底在干嘛.
警告: 不要 放置 黄赌毒 以及 时政 内容, 在 我党 这种 婊子当惯、牌坊耸立 的绝世老流氓跟前,那是在 找死.
这项技术对于 外国 在华 记者 更是重大利好, 不用费劲吧啦地到处找翻墙梯子, 直接在 于中国可访问的 境外自家网站上的 web 服务器上添加一个 反向代理 特殊 URL 条目, 单独部署一 SSRoT 服务器, 就可通过 SSRoT 客户端访问墙外内容了.
SSRoT 技术关键点
- 客户端是标准的 SOCKS5 服务器, 客户端 与远端 web 服务器 以 HTTPS 协议通讯, 通讯内容是协商升级成 WebSocket 协议, 协商成功后, 就以 WebSocket 协议进行基于长连接的数据交换, 直到某一方关闭连接.WebSocket 简明教程
- 交换的数据可经过 SS/SSR 加密算法处理, 甚至不用加密, 因为经 HTTPS 协议传输的内容, 包括请求路径URL, 数据等, 都是经过强加密的, GFW 破解不了, 即便 GFW 牛逼到真能破解了, 那 HTTPS 协议本身也就该升级换代了.
- 充当 反向代理 的 web 服务器必须有正式的域名, 有真正的数字证书. 这些可以通过 freenom.com 和 letsencrypt.org 免费 或 付费 获得, 后续的安装教程有详细讲解.
- 远端 反向代理 条目 URL 字串必须足够复杂, 足够随机, 以增加 GFW 穷举法猜算出来的难度. 一个随机生成的 UUID 字串就足够 GFW 喝一壶的, 况且我们也可以随时更换.
- 远端 反向代理 服务器采用市面上常见的 web 服务器软件就可以, 没特殊要求. 这彻底杜绝了 GFW 的被动检测和主动嗅探,因为网站是真实存在的,经得住 GFW 的各种威逼利诱。
- 与 反向代理 web 服务器进行通讯的 SSRoT 服务器也是基于 WebSocket 协议, 然后它将数据解包后转发到用户试图访问的 目标网站. 在收到 目标网站 的反馈信息以后, 它 将信息进行 加密, 封包后, 以 WebSocket 帧 发送给 反向代理 服务器, 反代 原封不动 地 转发给 SSRoT 客户端.
准备工作
进行 服务端配置工作 的人必须具有一定 Linux 使用经验, 像怎么注册 VPS (Virtual Private Server, 虚拟专用服务器), 怎么用 SSH 登录 VPS, 怎么使用工具软件 vi (文末有教程链接) 编辑文本文件以及一些 Linux 基本命令的使用, 等等. 如果你不会, 建议你去学会了再来尝试搭建 SSRoT.
- linux 命令行 bash 基本操作 或者 油管链接
- vi 视频教程 或者 油管链接
购买一个 VPS
这可以通过 信用卡, PayPal, 支付宝, 微信支付 等支付手段, 从 谷歌云, 亚马逊云, linode, digital ocean, bandwagonhost, vultr 等 VPS 服务商 购买. 对于个人用户, 一般 选择 年费 30 至 50 美元 档次的 足矣.
警告: 切勿购买 什么 阿里云, 腾讯云, 京东云 等受 我党 控制的 垃圾主机, 哪怕它速度快上天, 外表涂着蜂蜜的狗屎那也是狗屎. 你懂的.
购买之后, 请创建一台 虚拟主机 并让 它 运行起来, 注意防火墙设置, 必须开放 80 和 443 两个端口, 当然 ssh 使用的 22 端口也必须开放 (默认是开放的).
为了减少后续安装 SSRoT 时可能出现的各种奇奇怪怪的问题, 希望统一选择 ubuntu 18.04+ 版本的操作系统.
注册 一个 Domain (域名)
推荐使用 freenom 家的, 它提供有收费域名注册, 也允许免费域名注册, 更方便的是, 你可以把上一步刚创建的主机 IP 通过简单的设置就在这里与 域名 关联上.
freenom 教学视频 或者 油管链接
由于蝗虫一般涌入试图薅羊毛的中国人让 freenom 极度不满, freenom 的免费域名注册对中国人并不友好, 极大概率注册会失败. 为了顺利注册免费域名, 请首先用美国 IP 翻着墙, 使用 Google 账号直接登录该站, 不必自主注册账号, 在填写个人资料时, 胡诌个美国住址, 就可以随意注册免费域名了. 参考资料
将 域名 和 虚拟主机 的 IP 关联上
一般 域名 注册商都有域名解析服务, 各家设置界面都不相同, 其中就数 freenom 最简单, 亲民.
设置完成以后, 等待一两分钟, 就可以用 ping 命令试着将这个域名 ping 通. 看看域名和 IP 是不是对应上了.
关联后的域名像下图那个样子。 注意,必须把 www 也关联上,这很重要。否则后面的安装脚本在验证 www 域名时找不到主机,导致安装失败。
手工安装 SSRoT 服务器全程详解
对于需要定制化安装 SSRoT 服务器的用户, 本文提供了详细的讲解. 几乎涉及到安装的每个细节.
下面的操作全部在你的远程主机 VPS 上进行, 其操作系统最好是 ubuntu 18.04+
使用 ssh 软件从你电脑上登录远程主机 VPS.
ssh root@123.45.67.89 -p 22
上面的 123.45.67.89 是你 VPS 的 IP 地址, root 是远程主机上的账号名, 如果你的 VPS 的 ssh 端口 不是 22, 请替换成你自己的. 然后 盲打 输入 你的 VPS 登录 密码 登入 VPS.
提升操作权限到 root 权限.
sudo -i
预先安装一些必要的工具
apt-get update -y
apt-get install make zlib1g zlib1g-dev build-essential autoconf libtool openssl libssl-dev -y
apt install python3 python python-minimal cmake git wget -y
安装 web 服务器 nginx 软件
安装 web 服务器 nginx 软件. 命令为
apt-get install nginx -y
完毕以后, 可以敲入 nginx -v 查看 nginx 的版本号, 也可以通过命令 which nginx 查看 nginx 到底安装在哪个地方.
nginx 配置文件是 /etc/nginx/nginx.conf, 文件里有如下两行
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
第一行表明 /etc/nginx/conf.d/ 文件夹里所有 *.conf 都会被包含进配置里面, 目前这个文件夹是空的.
第二行表明 /etc/nginx/sites-enabled/ 文件夹内所有文件都会包含进配置, 目前只有一个文件 default, 因此该文件全路径即为 /etc/nginx/sites-enabled/default, 该文件内指明了 web 站点首页文件是 /var/www/html/index.html.
为了避免这个文件对我们以后的操作造成困惑、干扰. 把这个文件删了再说
rm -rf /etc/nginx/sites-enabled/default
创建我们的假站点文件夹 /fakesite, 并把样本主页文件复制到这里.
mkdir /fakesite
mkdir -p /fakesite/.well-known/acme-challenge/
cp /var/www/html/*.* /fakesite
在 /etc/nginx/conf.d/ 文件夹内创建 子 配置文件 ssr.conf, 并用 vi 软件进行编辑
rm -rf /etc/nginx/conf.d/*
vi /etc/nginx/conf.d/ssr.conf
通过 vi 输入如下内容
server {
listen 80;
server_name localhost;
index index.html index.htm index.nginx-debian.html;
root /fakesite;
}
然后使用下列命令让 nginx 重新加载配置使其生效
nginx -s stop
nginx
获取 数字安全证书
Let's Encrypt 是免费、自动化、开放的证书签发服务, 它得到了 Mozilla、Cisco、Akamai、Electronic Frontier Foundation 和 Chrome 等众多公司和机构的支持,发展十分迅猛。
申请 Let's Encrypt 证书不但免费,还非常简单,虽然每次只有 90 天的有效期,但可以通过脚本定期更新,配好之后一劳永逸。
以下命令就是配置过程. 注意, 下列命令不能简单地复制粘贴, 请将这些命令复制到文本编辑器里, 将里边的两处 mygoodsite.com 字串替换成你自己的 域名, 然后才可以复制粘贴到 ssh 的命令行终端控制台里.
org_pwd=`pwd`
mkdir /fakesite_cert
cd /fakesite_cert
openssl genrsa 4096 > account.key
openssl genrsa 4096 > domain.key
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:mygoodsite.com,DNS:www.mygoodsite.com")) > domain.csr
wget https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /fakesite/.well-known/acme-challenge/ > ./signed.crt
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
wget -O - https://letsencrypt.org/certs/isrgrootx1.pem > root.pem
cat intermediate.pem root.pem > full_chained.pem
cd ${org_pwd}
安装证书失败的绝大部分原因参阅 这里
经过这样一通骚操作, 我们就已经在 /fakesite_cert 文件夹里创建好了数字证书.
将 数字安全证书 部署到 web 服务器
将 原 web 服务器 配置文件 删掉, 再用 vi 软件重新生成 配置.
rm -rf /etc/nginx/conf.d/ssr.conf
vi /etc/nginx/conf.d/ssr.conf
通过 vi 输入如下内容, 注意 替换里边的 mygoodsite.com 字串为您的 域名
server {
listen 443 ssl;
ssl on;
ssl_certificate /fakesite_cert/chained.pem;
ssl_certificate_key /fakesite_cert/domain.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
server_name mygoodsite.com;
index index.html index.htm index.nginx-debian.html;
root /fakesite;
error_page 400 = /400.html;
location /5mhk8LPOzXvjlAut/ {
proxy_redirect off;
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
}
}
server {
listen 80;
server_name mygoodsite.com;
index index.html index.htm index.nginx-debian.html;
root /fakesite;
location /.well-known/acme-challenge/ {
}
location / {
rewrite ^/(.*)$ https://mygoodsite.com/$1 permanent;
}
}
注意
- 其中的三处 mygoodsite.com 字串, 替换成你自己的 域名.
- 5mhk8LPOzXvjlAut 字串就是 反向代理 的入口, 必须替换成你自己随机生成的字串, 不能偷懒, 否则 GFW 的网络爬虫会爬取到本网页, 将 5mhk8LPOzXvjlAut 加入破解词库, GFW 分分钟将你拿下.
- 大家可以看到, 该 location 节区有句 proxy_pass http://127.0.0.1:10000; 表明, 为 反代 提供服务的 SSR 服务器必须监听在 127.0.0.1:10000 上, 否则不能联动. 这表明 SSR 服务器也可以安装在另一台主机上监听另一端口, 只要把这里的 proxy_pass 值设置相应的正确值就没问题.
- 由于 vi 编辑器非常原始, 也不支持鼠标, 编辑文字极其不便, 建议在本地纯文本编辑器里弄好了以后, 一次性复制粘贴到 vi 编辑器里, 然后保存退出.
随机字串 的生成很简单, 如下命令足矣, 注意查看生成的字串, 如果含有斜杠 / 加号 + 或者等号 =, 就再次生成, 直到没有为止.
head -c 12 /dev/random | base64
最后使用下列命令使配置生效
nginx -s reload
证书自动更新 计划任务 设置
用 vi 在 /fakesite_cert 文件夹 创建 计划任务脚本 renew_cert.sh
vi /fakesite_cert/renew_cert.sh
通过 vi 输入如下内容
#!/bin/bash
cd /fakesite_cert/
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /fakesite/.well-known/acme-challenge/ > ./signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat signed.crt intermediate.pem > chained.pem
nginx -s reload
然后给这个文件赋予 可执行 属性
chmod +x /fakesite_cert/renew_cert.sh
将这个脚本写入 计划任务 crontab 中
service cron stop
rm -rf tmp_info
crontab -l > tmp_info
echo "0 0 1 * * /fakesite_cert/renew_cert.sh >/dev/null 2>&1" >> tmp_info && crontab tmp_info && rm -rf tmp_info
service cron start
安装 SSR 服务器
使用如下命令安装 SSR 服务器.
wget --no-check-certificate https://raw.githubusercontent.com/ShadowsocksR-Live/shadowsocksr-native/master/install/ssrn-install.sh
chmod +x ssrn-install.sh
./ssrn-install.sh 2>&1 | tee ssr-n.log
中间会要求你输入一些参数. 如果你懒, 一路回车也可以.
安装完毕以后, 用 vi 打开 SSR 配置文件 /etc/ssr-native/config.json
vi /etc/ssr-native/config.json
改成下面这个样子:
找到 server_settings 节区, 将监听端口 listen_port 的值替换成 10000 端口.
找到 client_settings 节区, 将 server_port 的值替换成 HTTPS web 服务器端口 443 端口.
找到 over_tls_settings 节区, 将 enable 的值改成 true, 将 server_domain 的值 mygoodsite.com 替换成你的 域名, 将 path 的值 5mhk8LPOzXvjlAut 替换成你前边生成的随机字串, 注意前后的斜杠 / 必须保留不能删了.
...
"server_settings": {
"listen_address": "0.0.0.0",
"listen_port": 10000
},
"client_settings": {
"server": "12.34.56.78",
"server_port": 443,
"listen_address": "0.0.0.0",
"listen_port": 1080
},
"over_tls_settings": {
"enable": true,
"server_domain": "mygoodsite.com",
"path": "/5mhk8LPOzXvjlAut/",
"root_cert_file": ""
}
然后再用 cat /etc/ssr-native/config.json 命令检查一下, 如果没问题就可以复制粘贴到本地作为客户端的 配置文件了.
最后使用如下命令重启 SSR 服务.
systemctl restart ssr-native.service
到此, 如果一切顺利, SSRoT 安装完成. 可以使用 ssr-client 客户端翻墙了.
当然. 这时候位于 /fakesite/ 文件夹内的网站内容, 还是一个孤零零的示例网页文件, 下一步您得尽快填补一些看起来有趣的内容. 否则, 等 GFW 醒过闷儿来, 就可能封杀这个网站了.
成果汇总
- web 服务器 nginx 安装后的可执行文件路径 /usr/sbin/nginx
- nginx 配置文件的根文件夹路径 /etc/nginx/
- nginx 针对假网站的配置文件全路径 /etc/nginx/conf.d/ssr.conf
- 假网站的根目录 /fakesite/
- 假网站的安全证书文件存放目录 /fakesite_cert/
- SSR 可执行文件的全路径 /usr/bin/ssr-server
- SSR 配置文件全路径 /etc/ssr-native/config.json
创建假网站
一般在您远程 Linux 虚拟主机上执行如下命令, 就可以把一静态网站下载到您主机上. 注意其中的网址 http://www.xxxyyyz.com/ 要改成您选定的某个已经存在的网站, 并且注意是 http 还是 https 不要搞错了. —— 不能偷懒, 因为 www.xxxyyyz.com 是我随手敲的, 它并不存在.
wget http://www.xxxyyyz.com/ -r --level=5 -p -np -k -m -e robots=off -U "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6"
这条命令很长, 我把参数稍微解释一下.
- -e robots=off 让 wget 耍流氓无视 robots.txt 协议
- -U "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6" 伪造 agent 信息
- -r 或者 --recursive specify recursive download. 递归下载
- --level=5 递归下载的层级, 我这里指定递归到 5 级就停止了, 否则没完没了撑爆您硬盘就不好玩了. 您可以按照您的需要调整.
- -p 或者 --page-requisites get all images, etc. needed to display HTML page. 下载页面所有文件,使页面能在本地打开
- -np 或者 --no-parent don't ascend to the parent directory. 不下载父级目录的文件
- -k 或者 --convert-links(转换链接) make links in downloaded HTML point to local files.(将下载的HTML页面中的链接转换为相对链接即本地链接)
- -m 或者 --mirror shortcut for -N -r -l inf --no-remove-listing
下载完成以后, 用 ls 命令可以查看到名为 www.xxxyyyz.com 的文件夹.
以命令 cd www.xxxyyyz.com 进入文件夹.
再以 ls 命令查看, 可以看到整个网站的文件, 注意看有没有 index.html 文件, 如果没有, 就有可能出错了, 您得换一个获取资源的网站, 再来一次.
如果一切正常, 敲入如下命令将这整个网站的文件移动到我们的假网站文件夹 /fakesite/ 里.
注意头一条命令是把假网站文件夹 /fakesite/ 里的原有文件都删了, 注意命令最后的星号 * 千万不能漏了. 然后第二条命令才是移动刚下载的文件到 /fakesite/ .
rm -rf /fakesite/*
mv * /fakesite/
目前为止, 我们的假网站就弄完了.
在您的浏览器里输入 您自己的网址域名访问这个假网站, 验证一下是否能加载出来.
客户端用法
客户端下载地址
这个客户端可用于 Windows, macOS, Linux 等系统。在 macOS 或 Linux 上可能得额外执行 chmod +x ./ssr-client 命令为软件加上 可执行 属性。
客户端运行命令
./ssr-client -c /your/path/of/config.json
Chrome 浏览器设置
打开 Chrome 浏览器, 点开菜单项 Windows -> Extensions, 在随后出现的 页面上 的 搜索框 里, 键入 SwitchyOmega, 找到这个插件, 安装上. 然后如下图进行设置.
最后在右上角的 那个 圈圈 图标上 点一下, 选择我们设置的条目. Chrome 就可以愉快地翻墙了.
FireFox 浏览器设置
macOS
其实上述的客户端用法已经可以在 macOS 上用起来了。
iOS
目前 iOS 端还没有弄好。不过有个变通的方法,用 iOS 上的 Potatso lite 以 SOCKS5 客户端的形式连接 台式机 上的 SSRoT 客户端,就可以用起来了。
在台式机上运行客户端, 注意配置文件里的设置
"client_settings": {
"server": "12.34.56.78",
"server_port": 12475,
"listen_address": "0.0.0.0",
"listen_port": 1080
},
监听地址是 0.0.0.0 表明你的手机可以用 连接 socks5 服务器的方式, 连上台式机上的 SSRoT 客户端. 只要在你手机上的代理软件上 的 s5 类型的服务器, 填上 台式机的 IP 和 监听端口 1080 就可以了. 如下图。
Android
安卓手机上客户端目前没有弄好,也可以用 iOS 类似的方法用起来。 辅助软件是 SocksDroid, 直接下载apk包 运行起来后如下图。
1 条评论:
去你妈的。。。傻B一个。。。
发表评论