修订代码,示例;修复ws的headers配置有些情况下匹配错误的bug

之前发现ws的header只设置了request,没设置response部分,这次都添加上了

且添加了ws的服务端 对于 额外header的验证
This commit is contained in:
e1732a364fed
2022-05-03 11:14:56 +08:00
parent faf322b212
commit bab6846c40
13 changed files with 391 additions and 261 deletions

View File

@@ -51,9 +51,9 @@ type Conf struct {
Host string
Addr netLayer.Addr
Path string
Headers map[string][]string //http headers
IsEarly bool //is 0-rtt or not; for quic and ws.
Extra map[string]any //quic: useHysteria, hysteria_manual, maxbyte; grpc: multiMode
Headers *httpLayer.HeaderPreset
IsEarly bool //is 0-rtt or not; for quic and ws.
Extra map[string]any //quic: useHysteria, hysteria_manual, maxbyte; grpc: multiMode
}
type Common interface {

View File

@@ -67,23 +67,27 @@ func (Creator) IsMux() bool {
return true
}
func getTunPath(sn string) string {
func getServiceNameFromConf(conf *advLayer.Conf) (serviceName string) {
if conf.Path != "" {
serviceName = conf.Path
} else {
serviceName = "GunService"
}
return
}
func getTunPath(serviceName string) string {
var sb strings.Builder
sb.Grow(1 + len(sn) + 4)
sb.Grow(1 + len(serviceName) + 4)
sb.WriteString("/")
sb.WriteString(sn)
sb.WriteString(serviceName)
sb.WriteString("/Tun")
return sb.String()
}
func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
var serviceName string
if conf.Path != "" {
serviceName = conf.Path
} else {
serviceName = "GunService"
}
serviceName := getServiceNameFromConf(conf)
c := &Client{
Config: Config{
@@ -105,19 +109,30 @@ func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
Proto: "HTTP/2",
ProtoMajor: 2,
ProtoMinor: 0,
Header: defaultClientHeader,
}
if conf.Headers != nil {
h := c.theRequest.Header.Clone()
for k, vs := range defaultClientHeader {
h.Add(k, vs[0])
}
c.theRequest.Header = h
} else {
c.theRequest.Header = defaultClientHeader
}
return c, nil
}
func (Creator) NewServerFromConf(conf *advLayer.Conf) (advLayer.Server, error) {
serviceName := getServiceNameFromConf(conf)
s := &Server{
Config: Config{
ServiceName: conf.Path,
ServiceName: serviceName,
Host: conf.Host,
},
path: getTunPath(conf.Path),
path: getTunPath(serviceName),
Headers: conf.Headers,
}
return s, nil

View File

@@ -20,6 +20,8 @@ type Server struct {
Config
Headers *httpLayer.HeaderPreset
http2.Server
path string

View File

@@ -10,6 +10,7 @@ import (
"net/url"
"github.com/e1732a364fed/v2ray_simple/advLayer"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/gobwas/ws"
@@ -23,11 +24,11 @@ type Client struct {
path string
UseEarlyData bool
headers map[string][]string
headers *httpLayer.HeaderPreset
}
// 这里默认传入的path必须 以 "/" 为前缀. 本函数 不对此进行任何检查
func NewClient(hostAddr, path string, headers map[string][]string, isEarly bool) (*Client, error) {
func NewClient(hostAddr, path string, headers *httpLayer.HeaderPreset, isEarly bool) (*Client, error) {
u, err := url.Parse("http://" + hostAddr + path)
if err != nil {
return nil, err
@@ -82,8 +83,11 @@ func (c *Client) Handshake(underlay net.Conn, ed []byte) (net.Conn, error) {
// 默认不给出Protocols的话, gobwas就不会发送这个header, 另一端也收不到此header
}
if len(c.headers) > 0 {
d.Header = ws.HandshakeHeaderHTTP(c.headers)
if c.headers != nil && c.headers.Request != nil && len(c.headers.Request.Headers) > 0 {
d.Header = ws.HandshakeHeaderHTTP(c.headers.Request.Headers)
//实测Header里的Connection会被用到。
}
br, _, err := d.Upgrade(underlay, c.requestURL)

View File

@@ -25,11 +25,11 @@ type Server struct {
UseEarlyData bool
Thepath string
headers map[string][]string
headers *httpLayer.HeaderPreset
}
// 这里默认: 传入的path必须 以 "/" 为前缀. 本函数 不对此进行任何检查.
func NewServer(path string, headers map[string][]string, UseEarlyData bool) *Server {
func NewServer(path string, headers *httpLayer.HeaderPreset, UseEarlyData bool) *Server {
return &Server{
//upgrader: upgrader,
@@ -85,6 +85,28 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
theWrongPath := ""
var thePotentialEarlyData []byte
var requestHeaderNotGivenCount int
noNeedToCheckRequestHeaders := s.headers == nil || s.headers.Request == nil || len(s.headers.Request.Headers) == 0
if !noNeedToCheckRequestHeaders {
requestHeaderNotGivenCount = len(s.headers.Request.Headers)
for k := range s.headers.Request.Headers {
switch k {
case "Host", "Connection", "Upgrade", "Sec-WebSocket-Version", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol", "Sec-WebSocket-Accept", "Sec-WebSocket-Extensions":
requestHeaderNotGivenCount -= 1
}
}
}
var responseHeader ws.HandshakeHeader
if s.headers != nil && s.headers.Response != nil && len(s.headers.Response.Headers) > 0 {
responseHeader = ws.HandshakeHeaderHTTP(s.headers.Response.Headers)
}
var theUpgrader *ws.Upgrader = &ws.Upgrader{
//因为我们vs的架构先统一监听tcp然后再调用Handshake函数
@@ -118,10 +140,32 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
}
return nil
},
}
OnHeader: func(key, value []byte) error {
if noNeedToCheckRequestHeaders {
return nil
}
vs := s.headers.Request.Headers[string(key)]
if len(vs) > 0 {
for _, v := range vs {
if v == (string(value)) {
requestHeaderNotGivenCount -= 1
break
}
}
}
if len(s.headers) > 0 {
theUpgrader.Header = ws.HandshakeHeaderHTTP(s.headers)
return nil
},
Header: responseHeader,
OnBeforeUpgrade: func() (header ws.HandshakeHeader, err error) {
if requestHeaderNotGivenCount > 0 {
if ce := utils.CanLogWarn("ws headers not match"); ce != nil {
ce.Write(zap.Int("requestHeaderNotGivenCount", requestHeaderNotGivenCount))
}
return nil, ws.RejectConnectionError(ws.RejectionStatus(http.StatusBadRequest))
}
return responseHeader, nil
},
}
if s.UseEarlyData {

View File

@@ -12,16 +12,32 @@ port = 4434
version = 0
insecure = true
utls = true
# advancedLayer = "ws" # ws也可应用我们的http header
advancedLayer = "ws" # ws也可应用我们的http header
path = "/very"
[dial.header.request]
version = "1.1"
method = "GET"
path = ["/very","/simple"] # 每次请求随机选择一个值。
version = "1.1" #如果你用ws, 则这一项不会被用到
method = "GET" #如果你用ws, 则这一项不会被用到
path = ["/very","/simple"] # 每次请求随机选择一个值。如果你用ws, 则这一项不会被用到
# 如果使用 ws, 则 Connection头必须指明为 Upgrade
#headers.Connection = [ "Upgrade" ]
#[dial.header.response]
# 如果使用 ws, 则 Connection头必须指明为 Upgrade, response 也一样
# 如果使用 ws, 则 dial的 Connection头必须指明为 Upgrade, 这是因为, headers配置的默认行为是如果你不给出header, 我们就会配置一个默认的header给你而默认的header的 Connection 是 keep-alive, 这个对于ws的握手是无效的。
headers.Connection = [ "Upgrade" ]
headers.mycustom1 = ["verysimple"]
headers.Host = ["www.baidu.com","www.bing.com"]
headers.User-Agent = [ "Mozilla/5.0 (my fake system)"]
headers.Accept-Encoding = [ "gzip, deflate" ]
headers.Pragma = ["no-cache"]
[dial.header.response]
# 如果使用 ws, 则 Connection头不用给出因为必须是Upgrade; 你给出也是可以的,但是会被无视。
#headers.Connection = [ "Upgrade" ]
headers.mycustom2 = ["verysimple_is_so_good"]

View File

@@ -9,8 +9,8 @@ fallback = ":80"
cert = "cert.pem"
key = "cert.key"
# advancedLayer = "ws"
advancedLayer = "ws"
path = "/very"
# 下面是 http伪装头的 配置
# 完全兼容v2ray, 可参考 https://www.v2fly.org/config/transport/tcp.html#httprequestobject
@@ -24,22 +24,28 @@ path = ["/very","/simple"] # 每次请求随机选择一个值。
# headers里的数组, 每次请求随机选择一个值。
# 如果使用 ws, 则 Connection头必须指明为 Upgrade
#headers.Connection = [ "Upgrade" ]
#headers.Host = ["www.baidu.com","www.bing.com"]
#headers.User-Agent = [ "Mozilla/5.0 (my fake system)"]
#headers.Accept-Encoding = [ "gzip, deflate" ]
#headers.Connection = [ "keep-alive" ]
#headers.Pragma = ["no-cache"]
# 如果使用 ws, 则 listen的 Connection头 不用给出因为必须是Upgrade; 你给出也是可以的,但是会被无视。
# 如果你给出的Header的首字母小写的则首字母自动被转换成大写.
headers.mycustom1 = ["verysimple"]
headers.Host = ["www.baidu.com","www.bing.com"]
headers.User-Agent = [ "Mozilla/5.0 (my fake system)"]
headers.Accept-Encoding = [ "gzip, deflate" ]
headers.Pragma = ["no-cache"]
# 还可以配置 response, 道理一样。这里直接省略了,就是使用默认值, 参考 v2ray文档。
#[listen.header.response]
# 如果使用 ws, 则 Connection头必须指明为 Upgrade, response 也一样
#headers.Connection = [ "Upgrade" ]
[listen.header.response]
# 如果使用 ws, 则 listen.header.response 的 Connection头必须指明为 Upgrade
headers.Connection = [ "Upgrade" ]
headers.mycustom2 = ["verysimple_is_so_good"]
[[dial]]
protocol = "direct"

View File

@@ -41,6 +41,34 @@ type HeaderPreset struct {
Response *ResponseHeader `toml:"response"`
}
// 将Header改为首字母大写
func (hh *HeaderPreset) Prepare() {
if hh.Request != nil && len(hh.Request.Headers) > 0 {
var realHeaders http.Header = make(http.Header)
for k, vs := range hh.Request.Headers {
for _, v := range vs {
realHeaders.Add(k, v)
}
}
hh.Request.Headers = realHeaders
}
if hh.Response != nil && len(hh.Response.Headers) > 0 {
var realHeaders http.Header = make(http.Header)
for k, vs := range hh.Response.Headers {
for _, v := range vs {
realHeaders.Add(k, v)
}
}
hh.Response.Headers = realHeaders
}
}
//默认值保持与v2ray的配置相同
func (hh *HeaderPreset) AssignDefaultValue() {
if hh.Request == nil {
@@ -89,6 +117,8 @@ func (hh *HeaderPreset) AssignDefaultValue() {
"Pragma": {"no-cache"},
}
}
hh.Prepare()
}
func (h *HeaderPreset) ReadRequest(underlay net.Conn) (err error, leftBuf *bytes.Buffer) {

174
iics.go Normal file
View File

@@ -0,0 +1,174 @@
package v2ray_simple
import (
"bytes"
"net"
"net/http"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"go.uber.org/zap"
)
//一个贯穿转发流程的关键结构
type incomingInserverConnState struct {
// 在多路复用的情况下, 可能产生多个 IncomingInserverConnState
// 共用一个 baseLocalConn, 但是 wrappedConn 各不相同。
baseLocalConn net.Conn // baseLocalConn 是来自客户端的原始传输层链接
wrappedConn net.Conn // wrappedConn 是层层握手后,代理层握手前 包装的链接,一般为tls层/高级层;
inServer proxy.Server //可为 nil
defaultClient proxy.Client
cachedRemoteAddr string
theRequestPath string
inServerTlsConn *tlsLayer.Conn
inServerTlsRawReadRecorder *tlsLayer.Recorder
isFallbackH2 bool
fallbackH2Request *http.Request
theFallbackFirstBuffer *bytes.Buffer
fallbackXver int
isTlsLazyServerEnd bool
shouldCloseInSerBaseConnWhenFinish bool
routedToDirect bool
RoutingEnv *proxy.RoutingEnv //used in passToOutClient
}
// 在调用 passToOutClient前遇到err时调用, 若找出了buf设置iics并返回true
func (iics *incomingInserverConnState) extractFirstBufFromErr(err error) bool {
if ce := utils.CanLogWarn("failed in inServer proxy handshake"); ce != nil {
ce.Write(
zap.String("handler", iics.inServer.AddrStr()),
zap.Error(err),
)
}
if !iics.inServer.CanFallback() {
iics.wrappedConn.Close()
return false
}
//通过err找出 并赋值给 iics.theFallbackFirstBuffer
{
fe, ok := err.(*utils.ErrBuffer)
if !ok {
// 能fallback 但是返回的 err却不是fallback err证明遇到了更大问题可能是底层read问题所以也不用继续fallback了
iics.wrappedConn.Close()
return false
}
if firstbuffer := fe.Buf; firstbuffer == nil {
//不应该至少能读到1字节的。
panic("No FirstBuffer")
} else {
iics.theFallbackFirstBuffer = firstbuffer
}
}
return true
}
//查看当前配置 是否支持fallback, 并获得回落地址。
// 被 passToOutClient 调用. 若 无fallback则 result < 0, 否则返回所使用的 PROXY protocol 版本, 0 表示 回落但是不用 PROXY protocol.
func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, result int) {
//先检查 mainFallback如果mainFallback中各项都不满足 or根本没有 mainFallback 再检查 defaultFallback
//一般情况下 iics.RoutingEnv 都会给出,但是 如果是 热加载、tproxy、go test、单独自定义 调用 ListenSer 不给出env 等情况的话, iics.RoutingEnv 都是空值
if iics.RoutingEnv != nil {
if mf := iics.RoutingEnv.MainFallback; mf != nil {
var thisFallbackType byte
theRequestPath := iics.theRequestPath
if iics.theFallbackFirstBuffer != nil && theRequestPath == "" {
var failreason int
_, _, theRequestPath, failreason = httpLayer.GetRequestMethod_and_PATH_from_Bytes(iics.theFallbackFirstBuffer.Bytes(), false)
if failreason != 0 {
theRequestPath = ""
}
}
fallback_params := make([]string, 0, 4)
if theRequestPath != "" {
fallback_params = append(fallback_params, theRequestPath)
thisFallbackType |= httpLayer.Fallback_path
}
if inServerTlsConn := iics.inServerTlsConn; inServerTlsConn != nil {
//默认似乎默认tls不会给出alpn和sni项获得的是空值,也许是因为我用了自签名+insecure,所以导致server并不会设置连接好后所协商的ServerName
// 而alpn则也是正常的, 不设置肯定就是空值
alpn := inServerTlsConn.GetAlpn()
if alpn != "" {
fallback_params = append(fallback_params, alpn)
thisFallbackType |= httpLayer.Fallback_alpn
}
sni := inServerTlsConn.GetSni()
if sni != "" {
fallback_params = append(fallback_params, sni)
thisFallbackType |= httpLayer.Fallback_sni
}
}
{
fromTag := iics.inServer.GetTag()
fbResult := mf.GetFallback(fromTag, thisFallbackType, fallback_params...)
if fbResult == nil {
fbResult = mf.GetFallback("", thisFallbackType, fallback_params...)
}
if ce := utils.CanLogDebug("Fallback check"); ce != nil {
if fbResult != nil {
ce.Write(
zap.String("matched", fbResult.Addr.String()),
)
} else {
ce.Write(
zap.String("no match", ""),
)
}
}
if fbResult != nil {
targetAddr = fbResult.Addr
result = fbResult.Xver
return
}
}
}
}
//默认回落, 每个listen配置 都可 有一个自己独享的默认回落
if defaultFallbackAddr := iics.inServer.GetFallback(); defaultFallbackAddr != nil {
targetAddr = *defaultFallbackAddr
result = 0
}
return
}

239
main.go
View File

@@ -4,11 +4,9 @@ import (
"bytes"
"crypto/tls"
"errors"
"flag"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"sync"
@@ -44,25 +42,28 @@ var (
var (
DirectClient, _, _ = proxy.ClientFromURL(proxy.DirectName + "://")
Tls_lazy_encrypt bool
Tls_lazy_secure bool
)
func init() {
//用于回落到h2c
var (
h2c_transport = &http2.Transport{
DialTLS: func(n, a string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(n, a)
},
AllowHTTP: true,
}
flag.BoolVar(&Tls_lazy_encrypt, "lazy", false, "tls lazy encrypt (splice)")
flag.BoolVar(&Tls_lazy_secure, "ls", false, "tls lazy secure, use special techs to ensure the tls lazy encrypt data can't be detected. Only valid at client end.")
}
h2c_PROXYprotocolAddrMap = make(map[string]*http2.Transport)
h2c_PROXYprotocolAddrMap_mutex sync.RWMutex
)
// ListenSer 函数 是本包 最重要的函数。可以 直接使用 本函数 来手动开启新的 自定义的 转发流程。
// 监听 inServer, 然后试图转发到一个 proxy.Client。如果env没给出则会转发到 defaultOutClient。
// 若 env 不为 nil, 则会 进行分流或回落。具有env的情况下可能会转发到 非 defaultOutClient 的其他 proxy.Client.
//
// 使用方式可以参考 tcp_test.go, udp_test.go or cmd/verysimple.
// Use cases: refer to tcp_test.go, udp_test.go or cmd/verysimple.
//
// 非阻塞. 返回的closer 用于 停止监听,若为 nil则表示监听失败。
// non-blocking. closer used to stop listening. It means listening failed if closer == nil,
func ListenSer(inServer proxy.Server, defaultOutClient proxy.Client, env *proxy.RoutingEnv) (closer io.Closer) {
var handleHere bool
@@ -157,74 +158,6 @@ func ListenSer(inServer proxy.Server, defaultOutClient proxy.Client, env *proxy.
return
}
type incomingInserverConnState struct {
// 在多路复用的情况下, 可能产生多个 IncomingInserverConnState
// 共用一个 baseLocalConn, 但是 wrappedConn 各不相同。
baseLocalConn net.Conn // baseLocalConn 是来自客户端的原始网络层链接
wrappedConn net.Conn // wrappedConn 是层层握手后,代理层握手前 包装的链接,一般为tls层or高级层;
inServer proxy.Server //可为 nil
defaultClient proxy.Client
cachedRemoteAddr string
theRequestPath string
inServerTlsConn *tlsLayer.Conn
inServerTlsRawReadRecorder *tlsLayer.Recorder
isFallbackH2 bool
fallbackH2Request *http.Request
theFallbackFirstBuffer *bytes.Buffer
fallbackXver int
isTlsLazyServerEnd bool
shouldCloseInSerBaseConnWhenFinish bool
routedToDirect bool
RoutingEnv *proxy.RoutingEnv //used in passToOutClient
}
// 在调用 passToOutClient前遇到err时调用, 若找出了buf设置iics并返回true
func (iics *incomingInserverConnState) extractFirstBufFromErr(err error) bool {
if ce := utils.CanLogWarn("failed in inServer proxy handshake"); ce != nil {
ce.Write(
zap.String("handler", iics.inServer.AddrStr()),
zap.Error(err),
)
}
if !iics.inServer.CanFallback() {
iics.wrappedConn.Close()
return false
}
//通过err找出 并赋值给 iics.theFallbackFirstBuffer
{
fe, ok := err.(*utils.ErrBuffer)
if !ok {
// 能fallback 但是返回的 err却不是fallback err证明遇到了更大问题可能是底层read问题所以也不用继续fallback了
iics.wrappedConn.Close()
return false
}
if firstbuffer := fe.Buf; firstbuffer == nil {
//不应该至少能读到1字节的。
panic("No FirstBuffer")
} else {
iics.theFallbackFirstBuffer = firstbuffer
}
}
return true
}
// handleNewIncomeConnection 会处理 网络层至高级层的数据,
// 然后将代理层的处理发往 handshakeInserver_and_passToOutClient 函数。
//
@@ -572,111 +505,8 @@ func handshakeInserver_and_passToOutClient(iics incomingInserverConnState) {
}
//查看当前配置 是否支持fallback, 并获得回落地址。
// 被 passToOutClient 调用. 若 无fallback则 result < 0, 否则返回所使用的 PROXY protocol 版本, 0 表示 回落但是不用 PROXY protocol.
func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, result int) {
//先检查 mainFallback如果mainFallback中各项都不满足 or根本没有 mainFallback 再检查 defaultFallback
//一般情况下 iics.RoutingEnv 都会给出,但是 如果是 热加载、tproxy、go test、单独自定义 调用 ListenSer 不给出env 等情况的话, iics.RoutingEnv 都是空值
if iics.RoutingEnv != nil {
if mf := iics.RoutingEnv.MainFallback; mf != nil {
var thisFallbackType byte
theRequestPath := iics.theRequestPath
if iics.theFallbackFirstBuffer != nil && theRequestPath == "" {
var failreason int
_, _, theRequestPath, failreason = httpLayer.GetRequestMethod_and_PATH_from_Bytes(iics.theFallbackFirstBuffer.Bytes(), false)
if failreason != 0 {
theRequestPath = ""
}
}
fallback_params := make([]string, 0, 4)
if theRequestPath != "" {
fallback_params = append(fallback_params, theRequestPath)
thisFallbackType |= httpLayer.Fallback_path
}
if inServerTlsConn := iics.inServerTlsConn; inServerTlsConn != nil {
//默认似乎默认tls不会给出alpn和sni项获得的是空值,也许是因为我用了自签名+insecure,所以导致server并不会设置连接好后所协商的ServerName
// 而alpn则也是正常的, 不设置肯定就是空值
alpn := inServerTlsConn.GetAlpn()
if alpn != "" {
fallback_params = append(fallback_params, alpn)
thisFallbackType |= httpLayer.Fallback_alpn
}
sni := inServerTlsConn.GetSni()
if sni != "" {
fallback_params = append(fallback_params, sni)
thisFallbackType |= httpLayer.Fallback_sni
}
}
{
fromTag := iics.inServer.GetTag()
fbResult := mf.GetFallback(fromTag, thisFallbackType, fallback_params...)
if fbResult == nil {
fbResult = mf.GetFallback("", thisFallbackType, fallback_params...)
}
if ce := utils.CanLogDebug("Fallback check"); ce != nil {
if fbResult != nil {
ce.Write(
zap.String("matched", fbResult.Addr.String()),
)
} else {
ce.Write(
zap.String("no match", ""),
)
}
}
if fbResult != nil {
targetAddr = fbResult.Addr
result = fbResult.Xver
return
}
}
}
}
//默认回落, 每个listen配置 都可 有一个自己独享的默认回落
if defaultFallbackAddr := iics.inServer.GetFallback(); defaultFallbackAddr != nil {
targetAddr = *defaultFallbackAddr
result = 0
}
return
}
var (
h2c_transport = &http2.Transport{
DialTLS: func(n, a string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(n, a)
},
AllowHTTP: true,
}
h2c_PROXYprotocolAddrMap = make(map[string]*http2.Transport)
h2c_PROXYprotocolAddrMap_mutex sync.RWMutex
)
//被 handshakeInserver_and_passToOutClient 和 handshakeInserver 的innerMux部分 调用。
// 会调用 dialClient_andRelay若isfallback为true传入的 wlc 和 udp_wlc 必须为niltargetAddr必须为空值。
// 会调用 dialClient_andRelay. 若isfallback为true传入的 wlc 和 udp_wlc 必须为niltargetAddr必须为空值。
func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Conn, udp_wlc netLayer.MsgConn, targetAddr netLayer.Addr) {
////////////////////////////// 回落阶段 /////////////////////////////////////
@@ -698,8 +528,12 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
url, _ := url.Parse(urlStr)
rq.URL = url
transport := h2c_transport
if fbResult > 0 {
var transport *http2.Transport
if fbResult == 0 {
transport = h2c_transport
} else if fbResult > 0 {
h2c_PROXYprotocolAddrMap_mutex.RLock()
transport = h2c_PROXYprotocolAddrMap[targetAddrStr]
@@ -915,13 +749,11 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
}
//dialClient 对实际client进行拨号处理传输层, tls层, 高级层等所有层级后,进行代理层握手。
// result = 0 表示拨号成功, result = -1 表示 拨号失败, result = 1 表示 拨号成功 并 已经自行处理了转发阶段(用于lazy和 innerMux ); -10 标识因为client为reject而关闭了连接。
// 在 dialClient_andRelay 中被调用。在udp为multi channel时也有用到
func dialClient(targetAddr netLayer.Addr,
client proxy.Client, xver int, fallbackFirstBuf *bytes.Buffer,
baseLocalConn,
// result = 0 表示拨号成功, result = -1 表示 拨号失败, result = 1 表示 拨号成功 并 已经自行处理了转发阶段(用于lazy和 innerMux ); -10 标识 因为 client为reject 而关闭了连接。
// 在 dialClient_andRelay 中被调用。在udp为multi channel时也有用到.
func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr,
client proxy.Client,
wlc net.Conn,
cachedRemoteAddr string,
isTlsLazy_clientEnd bool) (
//return values:
@@ -979,7 +811,7 @@ func dialClient(targetAddr netLayer.Addr,
if ce := utils.CanLogInfo("Request"); ce != nil {
ce.Write(
zap.String("from", cachedRemoteAddr),
zap.String("from", iics.cachedRemoteAddr),
zap.String("target", targetAddr.UrlString()),
zap.String("through", proxy.GetVSI_url(client)),
)
@@ -1074,7 +906,7 @@ func dialClient(targetAddr netLayer.Addr,
}
if xver > 0 && xver < 3 {
if xver := iics.fallbackXver; xver > 0 && xver < 3 {
utils.Debug("Trying to write proxy protocol head")
netLayer.WritePROXYprotocol(xver, wlc, clientConn)
@@ -1184,8 +1016,8 @@ advLayerHandshakeStep:
// rpc error: code = Unavailable desc = connection error: desc = "transport: failed to write client preface: tls: use of closed connection"
}
if baseLocalConn != nil {
baseLocalConn.Close()
if iics.baseLocalConn != nil {
iics.baseLocalConn.Close()
}
result = -1
return
@@ -1266,9 +1098,9 @@ advLayerHandshakeStep:
if !hasInnerMux {
//如果有内层mux要在dialInnerProxy函数里再读, 而不是在这里读
if fallbackFirstBuf != nil {
if iics.theFallbackFirstBuffer != nil {
firstPayload = fallbackFirstBuf.Bytes()
firstPayload = iics.theFallbackFirstBuffer.Bytes()
} else {
firstPayload = utils.GetMTU()
@@ -1468,7 +1300,7 @@ func dialClient_andRelay(iics incomingInserverConnState, targetAddr netLayer.Add
}
}
wrc, udp_wrc, realTargetAddr, clientEndRemoteClientTlsRawReadRecorder, result := dialClient(targetAddr, client, iics.fallbackXver, iics.theFallbackFirstBuffer, iics.baseLocalConn, wlc, iics.cachedRemoteAddr, isTlsLazy_clientEnd)
wrc, udp_wrc, realTargetAddr, clientEndRemoteClientTlsRawReadRecorder, result := dialClient(iics, targetAddr, client, wlc, isTlsLazy_clientEnd)
if result != 0 {
return
}
@@ -1514,11 +1346,8 @@ func dialClient_andRelay(iics incomingInserverConnState, targetAddr netLayer.Add
} else {
if iics.theFallbackFirstBuffer != nil {
udp_wrc.WriteMsgTo(iics.theFallbackFirstBuffer.Bytes(), targetAddr)
utils.PutBytes(iics.theFallbackFirstBuffer.Bytes())
if ffb := iics.theFallbackFirstBuffer; ffb != nil {
udp_wrc.WriteMsgTo(ffb.Bytes(), targetAddr)
}
atomic.AddInt32(&ActiveConnectionCount, 1)
@@ -1529,7 +1358,7 @@ func dialClient_andRelay(iics incomingInserverConnState, targetAddr netLayer.Add
netLayer.RelayUDP_separate(udp_wrc, udp_wlc, &targetAddr, &AllDownloadBytesSinceStart, &AllUploadBytesSinceStart, func(raddr netLayer.Addr) netLayer.MsgConn {
utils.Debug("Relaying UDP with MultiChannel,dialfunc called")
_, udp_wrc, _, _, result := dialClient(raddr, client, -1, iics.theFallbackFirstBuffer, iics.baseLocalConn, nil, "", false)
_, udp_wrc, _, _, result := dialClient(iics, raddr, client, nil, false)
if ce := utils.CanLogDebug("Relaying UDP with MultiChannel, dialfunc call returned"); ce != nil {
ce.Write(zap.Int("result", result))

View File

@@ -38,7 +38,7 @@ type DirectClient struct {
func (*DirectClient) Name() string { return DirectName }
//若 underlay 为nil则会对target进行拨号, 否则直接返回underlay
//若 underlay 为nil则会对target进行拨号, 否则返回underlay本身
func (d *DirectClient) Handshake(underlay net.Conn, firstPayload []byte, target netLayer.Addr) (result io.ReadWriteCloser, err error) {
if underlay == nil {

View File

@@ -318,11 +318,9 @@ func (s *ProxyCommonStruct) InitAdvLayer() {
if dc := s.dialConf; dc != nil {
var Headers map[string][]string
if dc.HttpHeader != nil {
if dc.HttpHeader.Request != nil {
Headers = dc.HttpHeader.Request.Headers
}
var Headers *httpLayer.HeaderPreset
if creator.CanHandleHeaders() {
Headers = dc.HttpHeader
}
advClient, err := creator.NewClientFromConf(&advLayer.Conf{
@@ -355,11 +353,10 @@ func (s *ProxyCommonStruct) InitAdvLayer() {
if lc := s.listenConf; lc != nil {
var Headers map[string][]string
if lc.HttpHeader != nil {
if lc.HttpHeader.Request != nil {
Headers = lc.HttpHeader.Response.Headers
}
var Headers *httpLayer.HeaderPreset
if creator.CanHandleHeaders() {
Headers = lc.HttpHeader
}
var certArray []tls.Certificate

View File

@@ -1,6 +1,7 @@
package v2ray_simple
import (
"flag"
"io"
"log"
"net"
@@ -15,8 +16,20 @@ import (
"go.uber.org/zap"
)
var (
Tls_lazy_encrypt bool
Tls_lazy_secure bool
)
const tlslazy_willuseSystemCall = runtime.GOOS == "linux" || runtime.GOOS == "darwin"
func init() {
flag.BoolVar(&Tls_lazy_encrypt, "lazy", false, "tls lazy encrypt (splice)")
flag.BoolVar(&Tls_lazy_secure, "ls", false, "tls lazy secure, use special techs to ensure the tls lazy encrypt data can't be detected. Only valid at client end.")
}
//grpc 这种多路复用的链接是绝对无法开启 lazy的, ws 理论上也只有服务端发向客户端的链接 内嵌tls时可以lazy但暂不考虑
func canLazyEncryptServer(inServer proxy.Server) bool {