-
Notifications
You must be signed in to change notification settings - Fork 2
Description
最近在搭建一个内网穿透服务器, 恢复移动教务系统的使用, 原来搭建起来十分简单, 并且go源码也很容易看懂
搭建教程参考这里: https://ubock.com/article/31
总体的思路是, 修改默认服务器地址, 然后编译一下就好了
因为是偷偷摸摸的, 所以客户端需要隐藏服务端的地址, 折腾了几个思路, 然后发现自己好笨...
昨晚在课室通宵了一个晚上去寻找部署位置, 然后却发现那些暴露出来的交换机是移动通信的, 不能直接上网, 卒放弃, 部署~ 只能运行在师弟们的电脑上面了~ 也就没有加密服务器地址的需求了~
一开始是考虑把ngrok.exe
ngrok.cfg
run.cmd
打包在一起的, 然后找了一些一些单文件打包工具....但是单文件打包工具大多数都是用于把那些需要安装的软件绿化成为单文件. 手动创建单文件的教程很少, 大多数都是捕获一个安装包的过程, 然后生成的, 所以放弃
然后, 才发现, 只需要把服务器地址给隐藏起来就好了, 所以去修改源码的默认地址, OK, 成功了, 但是还是可以通过反编汇工具Ollydbg搜索字符串就可以找到, 然后把地址拆分为非连续的字符串....
addr := ""
addr += defaultServerAddr
addr += "."
addr += "dee"
addr += "pk"
addr += "olo"
addr += "s"
addr += "."
addr += "cn"
addr += ":"
addr += "80"
addr += "83"
然后师弟建议使用VMProtect 3
来加壳, 效果果然不错
然而突然意识到, 其实抓一下包就可以的, 无论软件如何隐藏都是无用的, 哈哈哈, 没抓住问题重点就开始实现的坑. 导致做了很多无用功. 配置一个虚拟抓包工具无法捕获的虚拟网卡? 算了, 不折腾这个了
然后遇到的问题是, 一个端口给移动教务系统的主机用, 一个给自己的电脑, 那么如何开启?
一个的时候是这样开启的
> ./bin/ngrokd -tlsKey="assets/server/tls/snakeoil.key" -tlsCrt="assets/server/tls/snakeoil.crt" -domain="$NGROK_DOMAIN" -httpAddr=":8081" -httpsAddr=":8082" -tunnelAddr=":8083"
如果命令常驻的话使用, 学到个nohup [command] &
就是说一个进程开启一个服务端口8083, 那么想开另一个服务端口就是运行一个服务进程在其他端口即可
那么现在8083给移动教务系统的主机使用, 8086给自己的电脑使用, 后面调试也会变方便一些~
那么问题来了, 说明一个端口对应一个客户, 隧道嘛, 一对一, 如果想要增加一个隧道就变得略微繁琐了, 感觉可以有管理工具实现方便拓展, 就是喵到一个需求了~~
ngrok的原理猜测
局域网主机可以访问公网主机
局域网主机不能访问另一个局域网主机(需要做局域网的公网ip的端口映射, 把某些端口映射到对应的局域网ip和端口, 这里是没有映射的情况)
局域网主机可以向公网主机对应端口建立tcp链接
公网主机不能向局域网主机对应端口建立tcp链接
所以,局域网主机访问另一个局域网主机,就借用公网主机做中转
先把隧道打通: 局域网主机向公网主机建立tcp长连接
另一个局域网主机(可以访问公网的主机)->访问(发送http请求报文到8081端口)公网主机
公网主机利用和局域网主机建立好的tcp长连接, 转发http请求报文+报文接受端口信息
局域网主机送8083端口收到请求报文, 根据报文接受端口, 映射到本地对应的端口
然后原路返回请求报
看源码验证, 把workflow整理处理
发现golang
几个有意思的点:
- 函数多返回值, 原生支持, 那种没有中间数据结构转换, js则是通过解构语法糖来实现
- 类似乎升级为package概念, 摆脱花括号的限制, 支持不同类型单独文件储存, 就是可以更好的抽象
- golang是弱化基类型的感知, 强调由基类型组成的结构体或者package, 强类型语言和弱类型语言各取其长
- defer的执行机制, 可以允许方便做资源检查, 申请和释放的定义位置相近, 这样就不会不会记得释放资源了, 其提供放方向的执行流, 感觉好新奇~
- go 语句实现协程很方便, ngrok里面
heartbeat
和proxy
都是走协程的, 不过有些执行流和语法绑定起来了, 短时间没能理解 - 语法简洁, for , if , switch, 做了多余标识符的精简, 括号, switch的break, 应该是该为通过缩进来约定case的body, 还有写运算符的增强
<-
用于chan操作
看源码还有个惊喜的地方就是mvc运用~
在client/controller.go/Run方法底部
在ctl.model.Run的协程建立controll tcp长链接, 然后验证之后, 就发送隧道配置到服务端, 然后就开启一个heartbeat协程, 并且开始监听消息, 收到消息之的话, 就新建一个proxy协程来负责
源码有关键的流程解析, 理解起来比较容易
https://github.com/inconshreveable/ngrok/blob/master/src/ngrok/client/model.go#L299
不过proxy是这样实现转发的, 不懂其原理https://github.com/inconshreveable/ngrok/blob/master/src/ngrok/client/model.go#L401
m.connTimer.Time(func() {
localConn := tunnel.Protocol.WrapConn(localConn, mvc.ConnectionContext{Tunnel: tunnel, ClientAddr: startPxy.ClientAddr})
bytesIn, bytesOut := conn.Join(localConn, remoteConn)
m.bytesIn.Update(bytesIn)
m.bytesOut.Update(bytesOut)
m.bytesInCount.Inc(bytesIn)
m.bytesOutCount.Inc(bytesOut)
})
服务端的话, 从特定8081(http), 8082(https) 端口接受请求, 通过子域名做做分发, 生成消息, 发送到隧道客户端, 然后隧道客户端返回消息, 然后返回对应的响应报文, 感觉和反向代理差不多, 忽略其他类型控制消息的话
原理和猜测基本一致咯~
ngrok负载均衡
因为师弟比较厉害, 手里有贼多服务器, 国内4台, 不过都是1兆, 所以可以考虑做一层简单的负载均衡
现在的思路是, 建立4个隧道, 然后移动教务系统, 轮转来使用这个四个隧道, 通过代码来实现,, 比较简单
搜索了一下负载均衡的策略, 发现和和操作系统里面磁盘空间分配策略有点类似的味道~
http://www.cnblogs.com/shanyou/archive/2012/11/09/2763272.html
1/12号补充, 感觉核心点是NAT, 今天复习的计算机网络的时候看到了, 书本描述如下
通过NAT路由器的通信必须由专用网内网的主机发起
但是在NAT的机制下, 如何实现TCP的长连接, 还有NAT的地址转换表的更新机制书本都没有说.
在v站得到答案了「连接跟踪」~ 晚点再消化这部分内容
https://www.v2ex.com/t/422416#reply5
1/13
还是感觉这个这个把内网主机+端口映射到外网主机的端口, 会导致NAT网络会有映射数目的限制
负载均衡还可以这样做, 碉堡了
https://kb.cnblogs.com/page/188170/
1/29
猜测nginx的反向代理应该是报文转发, 如果使用tcp的反向代理效果应该会更好
http://www.firefoxbug.com/index.php/archives/2775/
主要区别是数据发送的时机, tcp的反向代理是每一个tcp发送了转发, http则需要响应请求报文的数据全部收取完成再做转发
还需要找更多资料验证猜测~
Activity
[-]ngrok服务端搭建, 多个服务端配置, 客户端服务地址隐藏[/-][+]ngrok服务端搭建, 多个服务端配置, 简单的负载均衡[/+][-]ngrok服务端搭建, 多个服务端配置, 简单的负载均衡[/-][+]ngrok服务端搭建, 多个服务端配置, 客户端服务器地址隐藏, 简单的负载均衡[/+]derekibw commentedon Jan 26, 2021
ngrok负载均衡你实现了吗,最近折腾这个一直没什么头绪,求加微信请教,我的微信:derekibw,谢谢。
deepkolos commentedon Jan 26, 2021
derekibw commentedon Jan 26, 2021
你说的师弟他是否实现了,能帮忙咨询下吗,自己琢磨这一块不知道从哪里搞,感谢!
deepkolos commentedon Jan 26, 2021
我师弟实现的负载均衡不是ngrok,是免费的教育网穿墙代理的定时刷新可用性切换到可用的代理上面去