v2ray / discussion

For general discussion over Project V development and usage.
298 stars 34 forks source link

rm #754

Closed 89650021 closed 3 years ago

89650021 commented 4 years ago

rm

RPRX commented 4 years ago

我觉得还是要标明一下灵感来源 https://github.com/v2ray/v2ray-core/issues/2552

不过网页的确比插件等轻量级一些,是个很好的思路

nodejs 那一层可以去掉,由 v2ray 内建实现

RPRX commented 4 years ago

具体思路就是,v2ray 监听一个本地端口,浏览器访问了特定的网页后,通过 ws 建立和 v2ray 的连接

v2ray 有数据需要发出时,推给浏览器,由浏览器包裹 TLS 后代发出(可以是 wss h2 h3 等)

RPRX commented 4 years ago

如果v2ray能自带outbound变为能接受websocket的被动连接的server 那本地的服务器就可以省下来了。

刚看到你有写,我觉得这是个更可行的方式。

89650021 commented 4 years ago

我觉得还是要标明一下灵感来源 v2ray/v2ray-core#2552

不过网页的确比插件等轻量级一些,是个很好的思路

nodejs 那一层可以去掉,由 v2ray 内建实现

确实是您先想到的。 我当初是看chrome 的devtools拿websocket连接的。试着用它的api去操作浏览器发送websocket总是各种问题,所以才想到这个的。。 现在有个问题是每次访问完网页v2ray服务端和客户端都会关闭websocket连接,网页这边我又不太会处理。客户端这边和本地的nodejs服务器的连接一直保持着所以不用管,但是v2ray服务器那边并不是这样。所以看了一个网页之后就得刷新重连。抄网上的各种autoreconnect代码效果很差,最后是在服务器那边的nginx前端后边也放了一个nodejs服务器连着v2ray服务器,保证一直连接着才解决的(也许可以把nginx扔了直接连nodejs?),感觉非常蠢。您当初的代码是怎么解决这些问题的? 还有一个问题是浏览器总会block掉不是同一origin的websocket连接。但如果把这个网页放到服务器那边感觉也不妥。我现在拿hosts+端口转发解决的,感觉也是非常蛋疼。

RPRX commented 4 years ago

@89650021

我曾经深入研究过前端,不过有段时间没写了。

现在有个问题是每次访问完网页v2ray服务端和客户端都会关闭websocket连接,网页这边我又不太会处理。客户端这边和本地的nodejs服务器的连接一直保持着所以不用管,但是v2ray服务器那边并不是这样。所以看了一个网页之后就得刷新重连。抄网上的各种autoreconnect代码效果很差,最后是在服务器那边的nginx前端后边也放了一个nodejs服务器连着v2ray服务器,保证一直连接着才解决的(也许可以把nginx扔了直接连nodejs?),感觉非常蠢。您当初的代码是怎么解决这些问题的?

你可以把网页本身当 nodejs 来用。 这个问题的根源是 v2ray 还没有适配,此外我觉得 v2ray 的 ws 很奇怪。

还有一个问题是浏览器总会block掉不是同一origin的websocket连接。但如果把这个网页放到服务器那边感觉也不妥。我现在拿hosts+端口转发解决的,感觉也是非常蛋疼。

加载本地页面时的 response header 加个允许跨域(指定域名)就解决了。 请求服务器时返回的 response header 加个允许跨域读取(指定域名如 localhost)就解决了。

89650021 commented 4 years ago

@89650021

我曾经深入研究过前端,不过有段时间没写了。

现在有个问题是每次访问完网页v2ray服务端和客户端都会关闭websocket连接,网页这边我又不太会处理。客户端这边和本地的nodejs服务器的连接一直保持着所以不用管,但是v2ray服务器那边并不是这样。所以看了一个网页之后就得刷新重连。抄网上的各种autoreconnect代码效果很差,最后是在服务器那边的nginx前端后边也放了一个nodejs服务器连着v2ray服务器,保证一直连接着才解决的(也许可以把nginx扔了直接连nodejs?),感觉非常蠢。您当初的代码是怎么解决这些问题的?

~你可以把网页本身当 nodejs 来用。~ 这个问题的根源是 v2ray 还没有适配,此外我觉得 v2ray 的 ws 很奇怪。

还有一个问题是浏览器总会block掉不是同一origin的websocket连接。但如果把这个网页放到服务器那边感觉也不妥。我现在拿hosts+端口转发解决的,感觉也是非常蛋疼。

~加载本地页面时的 response header 加个允许跨域(指定域名)就解决了。~ 请求服务器时返回的 response header 加个允许跨域读取(指定域名如 localhost)就解决了。

多谢。 今天又试着改进,为了调试方便把上行的代理服务改成了明文的socks5.写了些代码自动重连是没问题了,但是从第二次请求开始发了socks的握手头部v2ray服务器那边日志回应只有content canceled,再也不会继续进行下去。。想了很久也没搞懂是什么原因。

@shell909090 看您之前似乎已经实现过了这个想法。您介意分享一下当初的思路吗?

shell909090 commented 4 years ago

websocket可以被封装为net.Conn接口。浏览器浏览页面并启动转发,可以视为一个Dial。这样就构成了客户端和服务器端的一个TCP类连接。随后在上面跑一般协议就行。

shell909090 commented 4 years ago

另外,origin那边,修改一下请求头就行。

ghost commented 4 years ago

@89650021 Maybe you can try Electron, where you can integrate Chrome into nodejs code (which holds the server) and make them talk to each other using something like const { ipcRenderer } = require('electron');

or try to convince @klzgrad to integrate naive proxy into v2ray as a websocket transportation layer :)

klzgrad commented 4 years ago

我可以提供帮助,把Chrome网络栈打包成一个动态链接库。

但是要这里有一个写Go的人对接。主要有两个问题:一,Go与C++的FFI怎么操作,这个我不能负责。二,Go与C++的数据控制流怎么接起来。Chrome网络栈里与net.Conn对标的是https://source.chromium.org/chromium/chromium/src/+/master:net/socket/socket.h ,它的控制方式是异步回调,回调是由Chrome的libevent线程驱动的。这个是否能与Go接起来,我不能解答。

ghost commented 4 years ago

I agree that it may be very complicated to make such interface that force go to play nicely with libevent. Use the library from C++ would be way more convenient.

I would try to build a web-socket forwarder for v2ray, and maybe also a plugin for shadowsocks.

klzgrad commented 4 years ago

我重新整理一下工作内容

  1. 我会把naiveproxy拆掉,提取出一个功能界面很小的动态链接库libnaive,把Chrome的网络栈暴露出来。
  2. 需要某人来维护一个Go的封装库,把libnaive的接口Go化。我不精通Go,不能做这个维护的工作。
  3. 需要某人来选取Go里面合适的IO模型,好与Chrome的IO模型对接。Chrome net::Socket的IO模型是异步回调,net.Conn的IO模型是同步阻塞,不能直接对接。

这个工作的影响力是做好之后,可以给所有Go类程序提供Chrome的网络栈后端。

@tomac4t @darhwa 来看看?

shell909090 commented 4 years ago

我觉得这个工作不需要这么死板。鉴于v2ray的工作模式,并不会开太多的并发,实际上做成一个独立的socks5代理即可。跑在tcp或者unix socket上都行。这样任何语言只要启动一个子进程就能套用伪装,用处更大一点。

RPRX commented 4 years ago

@simon-on-gh Electron 太重了,目前看来第二种思路更合适

@klzgrad Go 调用 C++ 要通过 CGO,会影响 v2ray 的交叉编译

按 @shell909090 说的用 Socks5 等程序间通信方式比较优雅,也不仅限于 Go 语言能用了

成为一个新的独立项目,如果能做到建立纯 TLS 通道(RAW)则更好

或者像 Nginx 一样通过 HTTP 代理和 v2ray 通信,限定用 HTTP 的协议,没有 RAW 了

RPRX commented 4 years ago

我觉得起一个 HTTP 正向代理比较合适,省心。

但如果能做到建立纯 TLS 通道(RAW),只有 Socks5 就行。

ghost commented 4 years ago

@klzgrad

I also agree with @rprx and @shell909090 now.

Instead of a library, it may be easier to build a naiveproxy-like middle box that accepts socks5 with unencrypted HTTP1.1 (maybe also with WebSocket support) in it, and sends out Chrome-like TLS HTTP1.1+TLS/HTTP2/QUIC to the desired port.

It can be used for existing v2ray client (over websocket without tls and a forward socsk5 proxy ) and server (over websocket with tls).

And it may also be used by other programs who want to send out modern HTTP traffic without using any complicated tls library.

klzgrad commented 4 years ago

既然你这么说,为什么不把现在的naive.exe拿去用?做成library的优势是便于发行安装配置。我没有兴趣提供一个可执行程序。

交叉编译是什么问题?naiveproxy现在已经交叉编译了11个平台,都是实际有人用的平台。

ghost commented 4 years ago

@klzgrad

Does naiveproxy support converting unencrypted HTTP traffic to encrypted HTTP1.1+TLS/HTTP2/QUIC already? I thought it will warp the incoming TCP connection from the socks5 with a HTTP proxy CONNECT, which might not work with most HTTP CDN or load balance on cloud platforms. This will also require a naïve fork of Caddy forwardproxy or Naïve server which doesn't play very well with existing v2ray ecosystem, and makes it hard to implement authentications or ACL.

What I meant in the previous post was that we can abuse socks5 as an interface between client program and the naive-like middle box. The client tells the middle box that it wants to establish connection to target IP on port 443, then talk in plain HTTP, and the middle box can send out a encrypted Chrome-like traffic to target IP on port 443.

A library is even better. People can easily build such middle box using libnaive as a temporary solution, and eventually switch to libnaive. What we suggest is simply for making the transition faster for v2ray users.

RPRX commented 4 years ago

@klzgrad

Golang 本身有自己的一套可移植性体系,不涉及 C 代码或调用动态链接库时不开 CGO 就可以很方便地交叉编译到各个系统和架构。但如果涉及那些东西就比较复杂了,比如调用动态链接库的通用做法是通过 CGO 来间接调用(调用 windows 的 dll 还可以通过 syscall),此时要交叉编译到现在支持的所有平台,需要同时提供对应的 C 编译器(如果涉及到不同的 libc 则更麻烦)。而现在 v2ray 的交叉编译都是不开 CGO 直接编译的,所以不是说无法交叉编译或者有什么致命影响,只是按那种方式使用一点非 Go 的东西就要引入很多非必要的代码、大改现有的编译流程,还可能会带来未知的全局问题,并不是首选的解决方案。

在这里 library 和独立程序并没有很大区别,本质上都是调用,通信方式不同罢了,况且传输的本来就是网络流量。独立程序更解耦一些,可以换不同的版本,也可以被其它程序直接使用,不只限于 Go。

或者说相较于动态链接库,监听端口是一个更灵活、通用的接口。(突然有种微服务的感觉)

当然,如果你只对 library 有兴趣,我把它改成另一种接口并不是难事,很快就可以完成。

RPRX commented 4 years ago

https://guide.v2fly.org/advanced/outboundproxy.html

若用 Socks5 / HTTP 代理,看起来 v2ray 甚至不需要改代码。。。

于是我看到了这句话:

另外,使用了代理转发 streamSettings 会失效,即只能是非 TLS、无 HTTP 伪装的 TCP 传输协议。

其实 v2ray 的这个功能如果设计得当,再给 inbound 加上类似的功能,想象空间就无限大了

klzgrad commented 4 years ago

按那种方式使用一点非 Go 的东西就要引入很多非必要的代码

这不是正确的认知。Chrome的网络栈含有五百万行C++代码,v2ray有多少行代码?让它能被Go用起来已经是世界上没有人做过的一个奇迹了。

ghost commented 4 years ago

按那种方式使用一点非 Go 的东西就要引入很多非必要的代码

这不是正确的认知。Chrome的网络栈含有五百万行C++代码,v2ray有多少行代码?让它能被Go用起来已经是世界上没有人做过的一个奇迹了。

To me it feels more like allowing Go or other programming languages to control the web stack of Chrome, instead of JavaScript only.

And I believe you are the only one who can let the miracle happen. :)

klzgrad commented 4 years ago

如果有人可以承诺承担 https://github.com/v2ray/discussion/issues/754#issuecomment-650567745 里面2、3的工作,我这边也会开始。

RPRX commented 4 years ago

@klzgrad

如我所说:本质上都是调用,通信方式不同罢了,况且传输的本来就是网络流量。

现在流行云原生和微服务,功能解耦、通过网络调用方式消除不同语言/模块间链接隔阂带来的好处是显而易见的。这里确定非要用“紧密耦合”的方式实现这个“奇迹”?持保留意见。

以及,请不要断章取义,这是一句完整的话:而现在 v2ray 的交叉编译都是不开 CGO 直接编译的,所以不是说无法交叉编译或者有什么致命影响,只是按那种方式使用一点非 Go 的东西就要引入很多非必要的代码、大改现有的编译流程,还可能会带来未知的全局问题,并不是首选的解决方案。

至于让 Go 调用 Chrome 网络栈修改而来的 C++ 的动态链接库,这属于功能性的实现,只要肯花时间精力不会做不到的,毕竟这个功能只取决于代码。但是为了做到这一点而花费的时间精力,以及对 v2ray 编译流程的大改等后续影响和麻烦事,远不如用 Socks5,劳动成果还更灵活通用。解决方案是哪个简单优秀选哪个,不是偏要选难的。

当然,如果是 Rust 这种用 LLVM 的语言就没那么多折腾,至少更亲和一些。 或者说,如果 v2ray 是 Rust 写的,那我应该会更支持动态链接库的方案。

@simon-on-gh

WASM 了解一下。

darhwa commented 4 years ago

@klzgrad

做这个会不会投入产出比太低?毕竟他们看中的只是chrome的tls实现。

首先,golang不能直接跟c++交互,只能跟c。所以至少需要为所有可能被外部调用的类写一个c wrapper,为这个任务估计要先调研怎样搞一个parser来自动化完成。涉及到继承跟多态的地方,也许会有未知的麻烦。

然后,你也提到有IO模型不一致的问题。我对golang了解也不多,搜了下搜出https://github.com/tidwall/evio 和https://github.com/panjf2000/gnet 。它们是直接绕开golang的net包,重新实现一套传输层,应用层还需要用户自己造。为什么不做成跟自带net兼容?我只能推测非不愿也,实不能也。如果要做你说的2和3的话,估计也得替换掉自带net包。大公司为了具体需求重造部分轮子是很常见的,但是为了v2ray这样不可能拿钱的项目很难坚持得下去吧。这里有一个悖论:有实际利益相关的机场主们,却大多没有技术能力。

其实,chrome在这里能帮得上忙的部分,目前只有tls实现。若只是为了解决因前段时间的风波引发的“tls焦虑”,我觉得有简单得多的办法:在naiveproxy里实现个http反向代理模式,类似https://github.com/v2ray/discussion/issues/704#issuecomment-636501511 。或者连这都不用做,直接让v2ray流量从naiveproxy提供的http tunnel里走就行。v2ray目前是可以配置成这样用的,只是麻烦点。

klzgrad commented 4 years ago

你开发过微服务,还是只是听说过微服务?如果你亲自开发过产品级的微服务,就不会有那么积极的感觉了。

我没有反对你的结论“并不是首选的解决方案”。我是指出“按那种方式使用一点非 Go 的东西”这个前提说明了理念的巨大差异。你认为Chrome的网络栈对Go来说是“一点东西”,我认为是大改。这个价值取向不一样,简单说就是谈不拢,没什么。

@darhwa

使用Chrome网络栈不只是TLS,还有连接池、预连接、重连接、证书管理、错误处理这些行为都可以一并获得。

我前面说了接口会很小,个位数的函数,即使我手动写出一个C wrapper也不会给Go造成太多麻烦。有时候我觉得再聊下去可能我自己就把Go打包的方法学会了,比如这个 http://www.swig.org/Doc3.0/Go.html 。但是这个事情的性质是社区对接,我自娱自乐是没用的。

xiaokangwang commented 4 years ago

其实吧,现在我已经写了一个网页中转程序了,但是现在还没有开始向V2整合 https://github.com/xiaokangwang/BrowserBridge 网页和中转服务器之间的流量通过Mux进行连接复用。

89650021 commented 4 years ago

其实吧,现在我已经写了一个网页中转程序了,但是现在还没有开始向V2整合 https://github.com/xiaokangwang/BrowserBridge 网页和中转服务器之间的流量通过Mux进行连接复用。

能请教一下这么大的bridge.js是怎么写出来的?是bridgejs.js.map提到的那些文件翻译成的JavaScript吗?

ghost commented 4 years ago

其实吧,现在我已经写了一个网页中转程序了,但是现在还没有开始向V2整合 https://github.com/xiaokangwang/BrowserBridge 网页和中转服务器之间的流量通过Mux进行连接复用。

能请教一下这么大的bridge.js是怎么写出来的?是bridgejs.js.map提到的那些文件翻译成的JavaScript吗?

@89650021 Gopherjs

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 5 days