问: 有没有基于 http 的 frp 实现

2017-11-23 11:23:09 +08:00
 cy97cool

frp 是啥

类似反向代理,通过一台有公网 IP 的服务器中转使我们可以访问到 没有公网 IP 的服务

放张容易理解的图:

From: https://github.com/aploium/shootback

现在的情景

我自己的电脑 A 连入了内网,但不能直接连入互联网 或者说 网速有限制不能满足需求;

但外界的服务器 B 可以连上 A 提供的 http 服务 (由内网其他服务器转发),但仅仅支持普通的 http,不支持 websocket

需求是在这种情况下通过 B 向 A 发起 http 请求的方式实现 A 的连入互联网

场景的特殊性

A 想上网,但只能靠 B 向 A 主动发起 http 连接

B 发起 http 请求 和 A 的回应 必须完整后 才能抵达对方(长连接无效)

frp 不支持这种情景

frp、上图的 shootback 的客户端和服务端都需要 tcp 连接,并不能支持 http 协议的连接

reGeorg 也不支持这种情景

https://github.com/sensepost/reGeorg

reGeorg 可以把 web 服务变为 socks 代理,但本质上还是 B 通过 A 的方式去请求 A 能得到的资源(比如说 A 所在的内网资源),我这个需求是要反过来 A 通过 B 去访问外网

我的想法:

A 实现一个 socks5 代理 和 http 服务器,B 实现 http 客户端; 使用$$tap 来让上层应用走 A 的 socks5 代理上网

B 轮询 A 问有没有请求,如果有就记下来,与真实目标建立 socket 连接,下次 http 请求的时候带上请求的相应内容

目前我的实现是 B 开 100 个线程轮询 A,A 在 10s 内如果有请求就在 http 响应中给出请求内容(A 的 socket send 的内容)和 request id ; 10s 超时就让 B 继续轮询; B 收到回应后检查 request id 对应的 socket、往 socket 里面 send ; B 对每个 socket 循环 recv,有内容就发起对 A 的 http 请求,带上 request id 和 socket recv 得到内容

但在高并发的时候 A 与 B 之间的 http 通讯并不一定稳定,可能请求失败(丢包)、后来的请求先到达对方(乱序);感觉就要实现一个 http 之上的 tcp 协议。。。

多线程写起来也没把握,写炸了也不明不白;这种情景下的实现能不能用 select 或者 epoll

还有一个性能上的问题:这种情景下 socket send 一次相对原生的 tcp 而言代价就很高,但 socks5 代理 recv 以及 socket 连真实服务器 recv 可能不需要交互接连两次 /多次,这时候可以合并多次 recv 得到的内容以减轻代价(如下载大文件);但在 https 握手这种交互情况下,为了减轻延迟 recv 了一次就需要马上从真实服务器得到回应 上层应用才会发起下一个包,如果设计成每隔 1s 才发一次包就意味着 https 握手就需要 3~4s 才能完成。 可不可能实现智能判断 socket 一次 recv 后下一次 recv 多久后会到达

问问大佬们有啥项目实现了这种情景 或者 给点建议

2251 次点击
所在节点    问与答
16 条回复
cy97cool
2017-11-23 11:43:32 +08:00
需求忘了说一点: B 向 A 的 http 请求的传输速度是高于百兆的,我目前瞎写的实现了 20M/s 的下载速度,但日常使用不稳定

想实现低延迟稳定的日常使用和高带宽的下载速度
pqee
2017-11-23 11:48:16 +08:00
HTTP 协议的本质只是格式要求,即第一行写什么第二行写什么。没有 TCP 可以考虑 UDP,都没有就废了,做不到的。
pqee
2017-11-23 11:54:40 +08:00
仔细读了一下发现楼主已经走了很远了,佩服!

帮你 google 了一下 tcp over http,找到了几个不错的:github.com/jpillora/chisel stackoverflow.com/a/14115584
cy97cool
2017-11-23 12:35:02 +08:00
@pqee 感谢回复,
我看了看 chisel 本质上等同于 reGeorg,都是在让 B 走 http 请求 A(墙外)能访问的资源,

我的需求不是这样 而在于让 A(内网不能上网)借助 B 的 http 请求来上网
boyxupers
2017-11-23 13:05:15 +08:00
ssh -R ?
cy97cool
2017-11-23 13:27:40 +08:00
@boyxupers
这种情景不支持 tcp,只能对外提供短连接 http 服务
所以 ssh 不可用
jjianwen68
2017-11-23 13:36:06 +08:00
squid 可以不
boyxupers
2017-11-23 19:16:04 +08:00
@cy97cool 那么 http 不走 tcp 协议吗?

这里必然是得看限制具体是什么,如果可以 https,那么可以走 TLS 的 session ticket,如果不可以,模拟个 get 头,剩下的走 session ticket
iceheart
2017-11-23 19:34:11 +08:00
逆向端口转发,跟 http 没关系,就是 tcp over tcp, 所有基于 tcp 的协议都能支持。对应的是正向转发,链路对称加密传输的话,前边放个普通代理就翻 wall 了,类似 ss 功能。
逆向加正向组合能在任何位置连进任何物理可达的网络。
cy97cool
2017-11-23 20:44:15 +08:00
@boyxupers
限制是由于这个 http 服务是被反向代理的,这么说吧:
B 可以访问到 A,是走服务器 C 中转的,而服务器 C 会先等到完成一个请求再把请求结果返回,所以说只支持 http 短连接

我对 session ticket 的理解不多,我觉得自己用 uuid1()生成一个 request id 就行?
cy97cool
2017-11-23 20:52:45 +08:00
@iceheart 不是很理解大佬的想法,大佬要不要再给点关键词给我学习一个

这种情景下的限制就是接触不到底层的 tcp 的,B 不能访问到 A 的 tcp 端口 只能走服务器 C 按 http 协议访问 A (所以 B 并不完全物理可达 A 只是 http 可达)
在这种限制下一切基于 tcp 的端口转发都要自己重新实现

正向的方式很简单,B 要访问 A 发个 socket 请求转为 http 主动请求等着回应就好;
而反过来 A 是不能主动请求 B 的,只能 A 被动接受 B 的轮询
iceheart
2017-11-23 23:50:12 +08:00
不好意思,又看了一遍需求才发现 B 到 A 是要经过反向代理的。大方向上没的选,只能是用 http 做载体。具体实现上我提些建议。我不建议你去实现 socks5 或者 http 代理协议,因为这些可以在 B 端搭一个现成的。你只需要实现在 A 端 listen 一个端口,A 向这个端口发起的 tcp 连接会被 B 转到一个指定的 ip:port 就好。至于这个端口跑 http 代理还是 socks 代理,哪个方便你就布哪个,何必自己写呢?你只需实现关键的 tcp 转发就完了呀。

tcp over http 反向转发:
建议 1.要有一个固定数量的 http 请求池,来接受 A 的数据请求。
2.AB 两端维护一个 tcp 连接集合,有状态的。来源就是来自 A listen 的端口上的连接,状态的变更就源自 AB 两端的 TCP 连接。连接标识可以用 A 端的 fd。
3.通信,A->B : http 等待请求池里取一个发应答回去,就到 B 那边了。
B->A :新发一个 http post
4.连接池维护:A 收到 http 请求扔到等待请求池里。
A 每秒检测一次这个池,超一秒的就返回空 http 应答。
Arnie97
2017-11-24 01:23:38 +08:00
想说 chisel 来着,发现#4 已经否定了。我感觉你说的 A、B 方向问题可以通过再套一层来解决?我这里以 chisel 和 openvpn 举个例子,其他协议同理。
A 部署 chisel server,openvpn server
B 部署 chisel client,openvpn client
B 通过 chisel 转发,和 A 建立起 openvpn 连接
此时 A,B 之间已经可以互访了,在 B 上开 NAT,A 的路由指向 B 即可
Arnie97
2017-11-24 01:27:49 +08:00
另外,chisel 是 Go 写的,我不是很了解这门语言是怎么垃圾回收的,反正在我 128MB 内存的容器里没法长期稳定运行,跑了一段时间后会内存不足…
cy97cool
2017-11-24 09:46:55 +08:00
@iceheart 感谢大佬,确实我没必要自己实现 socks 代理
但似乎还是要自己实现丢包重传(反向代理 C 在高并发下不靠谱)和多次请求之间的有序性(继续怪 C 不靠谱),就感觉是自己在实现 tcp
cy97cool
2017-11-24 09:47:41 +08:00
@Arnie97 我来试试这个方案

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/408801

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX