深入浅出【迷雾通】之第一篇
正文开始:https://pincong.rocks/article/10365
速度很快、特别难封:迷雾通的翻墙协议niaucchi4是我自己根据ScrambleSuit等在学术界认可的协议写的,基于UDP并在保证性能的前提下有高强度的混淆和加密。niaucchi4即使通过机械学习也难以辨别(初步用各种机械学习算法做过实测)。迷雾通运营两年多了,官网也早被封了(说明不是没有被盯上),但协议从未被封。根据两年内几千个用户的反馈,迷雾通稳定性和速度都非常好,包括在十一等敏感期间。
我们不是来找茬,只是一起审视代码!
niaucchi4协议,我没有细读,但是大概看过来是跑在KCP协议上,KCP底层用的UDP。
因为KCP的协议有24字节的报文头,所以GFW可以很容易识别出KCP协议,并封杀。
我给作者讲一些事情,v2ray也曾经有人用过KCP和mKCP,都失败了。。。所以KCP这条路是走不通的。。。但是我相信niaucchi4协议仍然是很出色的~有空我去读读!
可能作者也发现KCP这条路走不通,所以改了下面的代码
func dialBridge(host string, cookie []byte) (net.Conn, error) {
// return niaucchi4.DialKCP(host, cookie)
conn, err := net.DialTimeout("tcp", host, time.Second*5)
if err != nil {
return nil, err
}
conn.(*net.TCPConn).SetKeepAlive(false)
return cshirt2.Client(cookie, conn)
}
把
niaucchi4.DialKCP(host, cookie)
给注释掉了,改成了tcp连接。。。
第一部分总结:因为用了KCP协议,通过牺牲带宽来提升网速30%,所以很快。但是KCP的特征太明显,所以直接被识别,无条件封杀了。。。
「傻瓜式」软件前所未有的私密性:基本上任何付费梯子都有一个问题,就是注册和支付很容易暴露自己的隐私。即使你用假电话注册,用门罗币付款,如果服务商是黑心的(或者被共匪控制),在同一个用户名下的活动时间久了也很可能足够推断出谁是谁。自己搭梯子也很难避免这个问题(VPS提供商同样有可能有问题)。与其相反,迷雾通使用一个基于blind signature的加密学概念来进行用户验证。简而言之,就是用户可以向翻墙代理证明自己是注册过并付费过的用户,而不透露自己是哪一个用户。这样,注册支付这种「敏感」信息就和浏览活动从数学上隔离了,尽管用户体验上和付费VPN基本一样,实际隐私可以和自由门之类的不记名软件媲美。(当然要完全私密的话强烈建议开双重代理+Tor)
这里是作者亲自告诉我代码在哪里,省了我很多时间,谢谢作者!
https://github.com/geph-official/next.geph.io/blob/master/src/billing/PlanPicker.jsx
https://github.com/geph-official/next.geph.io/blob/master/racket/billing.rkt
先看PlanPicker,划重点,通过Stripe付费的!所以我们代码里搜索stripe
const STRIPEKEY = "pk_live_Wk781YzANKGuLBl2NzFkRu5n00YdYjObFY";
作者stripe账号的公钥,类似TLS里的serverhello,证明你付费对象的身份
然后我们选择付费plan,付款成功以后会调用webhook函数,返回
customerEmail: 你的迷雾通用户名@receipts.geph.io
接下来看/racket/billing.rkt,我不懂lisp,不好意思!!!
我们来搜关键字吧!
首先,我们搜索webhook,看看webhook函数在干嘛。
这里,我看到了Erlang语言的模式匹配,现在看checkout.session.completed这个case
register-subscription // 这里说下 前缀、中缀、后缀表达式(逆波兰表达式) 发现很多程序员数据结构没学。。。光学设计模式了?
如果习惯了前缀表达式,估计代码就看懂了。。。我们就不细讲了。。。
接下来,我们搜索第二个关键字,query-,记住带减号!
看不懂lisp,但是可以看懂sql,看着sql,把大概搞懂了~
subscriptions,stripeSubs,users,invoices 这几张表是干嘛的,了解下就可以了。
第二部分总结:作者把银行卡信息和用户账号隔离,没法通过迷雾通账号,知道对应的银行卡号。
第三部分总结:因为第一部分的结论,kcp协议走不通,作者使用了tcp协议,所以客户端和网桥的交互代码就基本废了重写。。。
现在回过来说下geph-binder,就是一个 端口号9080的http服务器。。。甚至不是https?
客户端,通过TLS连接到CDN,因为用了前置域名,所以GFW无法区分内容是什么。
CDN转发请求给binder,我们只要看 cmd\geph-binder\main.go里的路由就好了
重点关注add-bridge,get-bridges, 【warpfronts 新加的,我还没看】
读到这里的时候,我挺好奇的,如果GFW,给binder发了add-bridge,然后用户调用了
get-bridges得到了GFW的钓鱼网桥,不就玩大了么?
然后,我发现有鉴权。所以鉴权部分,我去研究下。。。还没看第二篇给你们补上!
继续,我们说下get-bridges,客户端代码,调用 getBridges 函数的时候,会发送get-bridges请求给binder
这个时候,binder返回自己存储的4个bridges~
客户端,得到应答以后,就通过调用 dialBridge 去连接网桥【tcp协议,kcp协议已经废掉了】
第四部分总结:网桥代码在境外VPS部署,启动以后,通过给binder发送add bridges请求,把自己的信息发给binder,binder鉴权以后,存储到cache。以后客户端可以通过CDN访问binder得到网桥信息。
最后客户端通过tcp协议连接到网桥~
52 个评论

第五部分:也是今天最后的内容了。。。
因为我们只关心翻墙!所以我们的重点,是客户端如何到达网桥!
现在开始讲解:
1. 客户端调用 dialBridge,得到一个tcp连接,再调用cshirt2.Client(cookie, conn)
2.cshirt2 库 调用 dhGenKey() 生成密钥对,明文发送自己的公钥给服务端
3.服务端 明文发送网桥的公钥,调用 udhSecret函数,得到 chacha的密钥
4.返回 transport ,作为入参调用 connThroughBridge
5.向网桥发送 cmd【conn/feedback】和 exitName【us-sfo-01.exits.geph.io】
6.读取网桥的应答,收到表示没问题,将这个transport放到sessionMap里
=========================================
现在将socks5代理部分:
1.客户端收到 socks5请求以后 调用 remote, ok = sWrap.DialCmd("proxy", rmAddr)
2.从刚才的sessionMap拿出一个连接,发送 cmd【proxy 地址】,成功以后就是一次link了~
3.网桥这个tcp连接已经和exit节点做了link,所以直接转发给了exit节点
4.查看出口节点代码 cmd\geph-exit\handle.go ,搜索
然后自己读就好了,我觉得不难。。。
没有任何算法部分,单纯就是根据域名解析ip,然后判断是不是在黑名单,没问题就去直连,建立link
我觉得,exit节点没有任何我感兴趣的部分。。。没怎么读。。。
我在品葱的大总结~
ShadowSocks 就是 socks5 over AES
迷雾通 就是 socks5 over Chacha20
v2ray 网上主流 方式 vmess over WSS【websocket over TLS】
沉默的广场提供的v2ray方式 socks5 over WSS【websocket over TLS】
Tor的meek网桥 就是 socks5 over https【http over TLS】
lantern 这个是lampshade协议,纯私有 ,但是代码完全开源???
另外大家都用到CDN,除了v2ray用了CDN的反向代理
还提供了很多静态资源下载方式
这里列举下lantern的地址
http://config.getiantem.org/proxies.yaml.gz
http://d2wi0vwulmtn99.cloudfront.net/proxies.yaml.gz
http://config-staging.getiantem.org/proxies.yaml.gz
http://d33pfmbpauhmvd.cloudfront.net/proxies.yaml.gz
这里列举下tor的meek
https://meek.azureedge.net/
这里列举下迷雾通的
http://1680337695.rsc.cdn77.org
http://loving-bell-981479.netlify.com
http://gephbinder-vzn.azureedge.net
最后,再次感谢 @为啥改名还要葱 赠送的1600 葱!!!
希望更多人给我送葱~
我会写感谢列表,每个人都可以得到感谢~
因为我们只关心翻墙!所以我们的重点,是客户端如何到达网桥!
现在开始讲解:
1. 客户端调用 dialBridge,得到一个tcp连接,再调用cshirt2.Client(cookie, conn)
2.cshirt2 库 调用 dhGenKey() 生成密钥对,明文发送自己的公钥给服务端
3.服务端 明文发送网桥的公钥,调用 udhSecret函数,得到 chacha的密钥
4.返回 transport ,作为入参调用 connThroughBridge
5.向网桥发送 cmd【conn/feedback】和 exitName【us-sfo-01.exits.geph.io】
6.读取网桥的应答,收到表示没问题,将这个transport放到sessionMap里
=========================================
现在将socks5代理部分:
1.客户端收到 socks5请求以后 调用 remote, ok = sWrap.DialCmd("proxy", rmAddr)
2.从刚才的sessionMap拿出一个连接,发送 cmd【proxy 地址】,成功以后就是一次link了~
3.网桥这个tcp连接已经和exit节点做了link,所以直接转发给了exit节点
4.查看出口节点代码 cmd\geph-exit\handle.go ,搜索
case "proxy":
然后自己读就好了,我觉得不难。。。
没有任何算法部分,单纯就是根据域名解析ip,然后判断是不是在黑名单,没问题就去直连,建立link
我觉得,exit节点没有任何我感兴趣的部分。。。没怎么读。。。
我在品葱的大总结~
ShadowSocks 就是 socks5 over AES
迷雾通 就是 socks5 over Chacha20
v2ray 网上主流 方式 vmess over WSS【websocket over TLS】
沉默的广场提供的v2ray方式 socks5 over WSS【websocket over TLS】
Tor的meek网桥 就是 socks5 over https【http over TLS】
lantern 这个是lampshade协议,纯私有 ,但是代码完全开源???
另外大家都用到CDN,除了v2ray用了CDN的反向代理
还提供了很多静态资源下载方式
这里列举下lantern的地址
http://config.getiantem.org/proxies.yaml.gz
http://d2wi0vwulmtn99.cloudfront.net/proxies.yaml.gz
http://config-staging.getiantem.org/proxies.yaml.gz
http://d33pfmbpauhmvd.cloudfront.net/proxies.yaml.gz
这里列举下tor的meek
https://meek.azureedge.net/
这里列举下迷雾通的
http://1680337695.rsc.cdn77.org
http://loving-bell-981479.netlify.com
http://gephbinder-vzn.azureedge.net
最后,再次感谢 @为啥改名还要葱 赠送的1600 葱!!!
希望更多人给我送葱~
我会写感谢列表,每个人都可以得到感谢~