修订代码,注释,示例

This commit is contained in:
hahahrfool
2022-03-29 21:58:23 +08:00
parent b63b90400a
commit 01d681f14f
7 changed files with 99 additions and 80 deletions

View File

@@ -25,10 +25,10 @@ host = "127.0.0.1" # 必填, 可填ip或域名如果 network是unix的话
port = 10800 # 必填 port = 10800 # 必填
[[dial]] [[dial]]
tag = "my_vlesss1" # 可选, 但不可与其他tag重复 tag = "my_vlesss1" # 同listen对应配置, 可选, 但不可与其他tag重复
protocol = "vlesss" # vless 的 尾缀s 表示 使用tls protocol = "vlesss" # vless 的 尾缀s 表示 使用tls
uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003" # 这个只是一个示例uuid,请自己生成一个新的. uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003" # 这个只是一个示例uuid,请自己生成一个新的.
host = "127.0.0.1" host = "127.0.0.1" # 同listen对应配置, 可填ip或域名如果 network是unix的话要填一个文件名(不需要已存在,可以是完整路径).
#network = "udp" #network = "udp"
# network 目前支持 tcp,udp 和unix;如果不给出则默认为 tcp; dial和listen都可配置此项 # network 目前支持 tcp,udp 和unix;如果不给出则默认为 tcp; dial和listen都可配置此项
@@ -47,7 +47,7 @@ host = "127.0.0.1"
# 除了在 protocol 字段使用 s尾缀 之外还可以明示使用tls. # 除了在 protocol 字段使用 s尾缀 之外还可以明示使用tls.
# 这两种方法不可重复使用.我们首选前者, 更简约, 当然如果你使用时需要频繁开关tls那么可以单独列出来 便于配置 # 这两种方法不可重复使用.我们首选前者, 更简约, 当然如果你使用时需要频繁开关tls那么可以单独列出来 便于配置
port = 4433 port = 4433 # 必填
version = 0 # 协议版本, 可省略, 省略则默认为最老版本 version = 0 # 协议版本, 可省略, 省略则默认为最老版本
insecure = true # 我们示例使用自签名证书,所以要开启 insecure. 实际场合请使用真证书并关闭 insecure insecure = true # 我们示例使用自签名证书,所以要开启 insecure. 实际场合请使用真证书并关闭 insecure
utls = true #是否使用 utls 来应用 chrome指纹进行伪装 utls = true #是否使用 utls 来应用 chrome指纹进行伪装

View File

@@ -3,7 +3,7 @@ package grpc
import ( import (
"context" "context"
"net" "net"
sync "sync" "sync"
"time" "time"
"github.com/hahahrfool/v2ray_simple/netLayer" "github.com/hahahrfool/v2ray_simple/netLayer"
@@ -21,11 +21,11 @@ var (
type ClientConn *grpc.ClientConn type ClientConn *grpc.ClientConn
/* /*
调用过程 建立新客户端连接的调用过程
先用 GetEstablishedConnFor 看看有没有已存在的 clientConn 先用 GetEstablishedConnFor 看看有没有已存在的 clientConn
没有已存在的自己先拨号tcp然后拨号tls然后把tls连接 传递给 ClientHandshake, 生成一个 clientConn 没有 已存在的自己先拨号tcp然后拨号tls然后把tls连接 传递给 ClientHandshake, 生成一个 clientConn
然后把获取到的 clientConn传递给 DialNewSubConn, 获取可用的一条 grpc 连接 然后把获取到的 clientConn传递给 DialNewSubConn, 获取可用的一条 grpc 连接
@@ -34,16 +34,18 @@ type ClientConn *grpc.ClientConn
//获取与 某grpc服务器的 已存在的grpc连接 //获取与 某grpc服务器的 已存在的grpc连接
func GetEstablishedConnFor(addr *netLayer.Addr) ClientConn { func GetEstablishedConnFor(addr *netLayer.Addr) ClientConn {
clientconnMutex.RLock() clientconnMutex.RLock()
clieintconn := clientconnMap[addr.GetHashable()] clientconn := clientconnMap[addr.GetHashable()]
clientconnMutex.RUnlock() clientconnMutex.RUnlock()
if clieintconn == nil { if clientconn == nil {
return nil return nil
} }
if (*grpc.ClientConn)(clieintconn).GetState() != connectivity.Shutdown { if (*grpc.ClientConn)(clientconn).GetState() != connectivity.Shutdown {
return clieintconn return clientconn
} }
//如果state是shutdown的话我们也不用特地清除map因为下一次申请就会覆盖map中的该项.
//如果底层tcp被关闭state就会为 Shutdown
return nil return nil
} }
@@ -51,10 +53,11 @@ func GetEstablishedConnFor(addr *netLayer.Addr) ClientConn {
//该 underlay一般为 tls连接。 addr为实际的远程地址我们不从 underlay里获取addr,避免转换. //该 underlay一般为 tls连接。 addr为实际的远程地址我们不从 underlay里获取addr,避免转换.
func ClientHandshake(underlay net.Conn, addr *netLayer.Addr) (ClientConn, error) { func ClientHandshake(underlay net.Conn, addr *netLayer.Addr) (ClientConn, error) {
//v2ray的实现中用到了一个 globalDialerMap[dest], 可以利用现有连接, // 用到了一个 clientconnMap , 可以利用现有连接,
// 只有map里没有与对应目标远程地址的连接的时候才会拨号; // 只有map里没有与对应目标远程地址的连接的时候才会拨号;
// 这 应该就是一种mux的实现 // 这就是一种mux的实现
// 如果有之前过的client的话直接利用现有client进行 NewStream, 然后服务端的话, 实际上会获得到第二条连接; // 如果有之前拨号过的client的话直接利用现有client进行 NewStream,
// 然后服务端的话, 实际上会获得到同一条tcp链接上的第二条子连接;
//也就是说,底层连接在客户端-服务端只用了一条,但是 服务端处理时却会抽象出 多条Stream连接进行处理 //也就是说,底层连接在客户端-服务端只用了一条,但是 服务端处理时却会抽象出 多条Stream连接进行处理
@@ -84,7 +87,8 @@ func ClientHandshake(underlay net.Conn, addr *netLayer.Addr) (ClientConn, error)
//在一个已存在的grpc连接中 进行新的子连接申请 //在一个已存在的grpc连接中 进行新的子连接申请
func DialNewSubConn(path string, clientconn ClientConn, addr *netLayer.Addr) (net.Conn, error) { func DialNewSubConn(path string, clientconn ClientConn, addr *netLayer.Addr) (net.Conn, error) {
//不像服务端需要自己写一个实现StreamServer接口的结构, 我们Client端直接可以调用函数生成 StreamClient // 帮助理解:
// 不像服务端需要自己写一个实现StreamServer接口的结构, 我们Client端直接可以调用函数生成 StreamClient
// 这也是grpc的特点, 客户端只负责 “调用“ ”service“而具体的service的实现 是在服务端. // 这也是grpc的特点, 客户端只负责 “调用“ ”service“而具体的service的实现 是在服务端.
streamClient := NewStreamClient((*grpc.ClientConn)(clientconn)).(StreamClient_withName) streamClient := NewStreamClient((*grpc.ClientConn)(clientconn)).(StreamClient_withName)

View File

@@ -9,8 +9,8 @@ import (
) )
// google.golang.org/grpc.(*Server).handleRawConn // google.golang.org/grpc.(*Server).handleRawConn
//go:linkname HandleRawConn google.golang.org/grpc.(*Server).handleRawConn //go:linkname handle_grpcRawConn google.golang.org/grpc.(*Server).handleRawConn
func HandleRawConn(c *grpc.Server, lisAddr string, rawConn net.Conn) func handle_grpcRawConn(c *grpc.Server, lisAddr string, rawConn net.Conn)
//Server实现 grpc生成的 StreamServer 接口,用于不断处理一个客户端传来的新需求 //Server实现 grpc生成的 StreamServer 接口,用于不断处理一个客户端传来的新需求
type Server struct { type Server struct {
@@ -25,15 +25,17 @@ type Server struct {
} }
// StartHandle方法 被用于 手动给 grpc提供新连接. // StartHandle方法 被用于 手动给 grpc提供新连接.
// 在本作中 我们不使用 grpc的listen的方法。 // 在本作中 我们不使用 grpc的listen的方法。这样更加灵活.
//非阻塞, //非阻塞.
func (s *Server) StartHandle(conn net.Conn) { func (s *Server) StartHandle(conn net.Conn) {
//非阻塞,因为 grpc.(*Server).handleRawConn 是非阻塞的里面用了新的goroutine //非阻塞,因为 grpc.(*Server).handleRawConn 是非阻塞的里面用了新的goroutine
HandleRawConn(s.gs, "", conn) handle_grpcRawConn(s.gs, "", conn)
} }
// 该 Tun方法会被 grpc包调用, stream_TunServer就是获取到的新连接; // 该 Tun方法会被 grpc包调用, stream_TunServer就是获取到的新连接;
// 实际上就是在 handle_grpcRawConn 后, 每一条客户端发来的子连接 都会调用一次 s.Tun .
//
// 我们把该 stream_TunServer 包装成 net.Conn 并传入 NewConnChan // 我们把该 stream_TunServer 包装成 net.Conn 并传入 NewConnChan
// 该方法是自动调用的, 我们不用管. // 该方法是自动调用的, 我们不用管.
func (s *Server) Tun(stream_TunServer Stream_TunServer) error { func (s *Server) Tun(stream_TunServer Stream_TunServer) error {
@@ -66,7 +68,7 @@ func NewServer(serviceName string) *Server {
newConnChan := make(chan net.Conn, 10) newConnChan := make(chan net.Conn, 10)
s := &Server{ s := &Server{
NewConnChan: newConnChan, NewConnChan: newConnChan, //该NewConnChan目前是永远不会被关闭的, 因为我们始终在监听新连接
gs: gs, gs: gs,
serviceName: serviceName, serviceName: serviceName,
} }

74
main.go
View File

@@ -399,9 +399,8 @@ func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy
for { for {
newGConn, ok := <-grpcs.NewConnChan newGConn, ok := <-grpcs.NewConnChan
if !ok { if !ok {
if utils.CanLogErr() { if utils.CanLogWarn() {
log.Println("upgrade grpc not ok") log.Println("grpc getNewSubConn not ok")
} }
iics.baseLocalConn.Close() iics.baseLocalConn.Close()
@@ -706,35 +705,34 @@ afterLocalServerHandshake:
// server也一样会在特定的场合给 CRUMFURS 传值这个机制是与main函数无关的 // server也一样会在特定的场合给 CRUMFURS 传值这个机制是与main函数无关的
// 而且 wrappedConn 会被 inServer 保存起来,用于后面的 unknownRemoteAddrMsgWriter // 而且 wrappedConn 会被 inServer 保存起来,用于后面的 unknownRemoteAddrMsgWriter
return return
} else { } else {
//如果不是CRUMFURS命令那就是普通的针对某udp地址的连接见下文 uniExtractor 的使用 //如果不是CRUMFURS命令那就是普通的针对某udp地址的连接见下文 uniExtractor 的使用
//defer wrappedConn.Close()
iics.shouldCloseBaseConnAfterCopyComplete = true iics.shouldCloseBaseConnAfterCopyComplete = true
} }
case "socks5": case "socks5":
// UDP Associate // UDP Associate
//
// 因为socks5的 UDP Associate 办法是较为特殊的不使用现有tcp而是新建立udp所以此时该tcp连接已经没用了 // 因为socks5的 UDP Associate 办法是较为特殊的不使用现有tcp而是新建立udp所以此时该tcp连接已经没用了
// 另外,此时 targetAddr.IsUDP 只是用于告知此链接是udp Associate并不包含实际地址信息 // 另外,此时 targetAddr.IsUDP 只是用于告知此链接是udp Associate并不包含实际地址信息
//但是根据socks5标准这个tcp链接同样是 keep alive的否则客户端就会认为服务端挂掉了. //但是根据socks5标准这个tcp链接同样是 keep alive的否则客户端就会认为服务端挂掉了.
default: default:
//defer wrappedConn.Close()
iics.shouldCloseBaseConnAfterCopyComplete = true iics.shouldCloseBaseConnAfterCopyComplete = true
} }
} else { } else {
if !(iics.isTlsLazyServerEnd) {
//lazy_encrypt情况比较特殊 //lazy_encrypt情况比较特殊基础连接何时被关闭会在tlslazy相关代码中处理。
// 如果不是lazy的情况的话转发结束后要自动关闭 // 如果不是lazy的情况的话转发结束后要自动关闭
//defer wrappedConn.Close() if !iics.isTlsLazyServerEnd {
iics.shouldCloseBaseConnAfterCopyComplete = true
//实测 grpc.Conn 被调用了Close 也不会实际关闭连接而是会卡住阻塞直到底层tcp连接被关闭后才会返回
// 但是我们还是 直接避免这种情况
if !inServer.IsMux() {
iics.shouldCloseBaseConnAfterCopyComplete = true
}
} }
@@ -742,7 +740,7 @@ afterLocalServerHandshake:
// 下面一段代码 单独处理 udp承载数据的特殊转发。 // 下面一段代码 单独处理 udp承载数据的特殊转发。
// //
// 这里只处理 vless v1 的CRUMFURS 转发到direct的情况 以及 socks5 的udp associate 转发到vless v1的情况; // 这里只处理 vless v1 的CRUMFURS 转发到direct的情况 以及 socks5 的udp associate 转发到vless 的情况;
// 如果条件不符合则会跳过而进入下一阶段 // 如果条件不符合则会跳过而进入下一阶段
if targetAddr.IsUDP() { if targetAddr.IsUDP() {
@@ -791,11 +789,11 @@ afterLocalServerHandshake:
// 将 outClient 视为 UDP_Putter 就可以转发udp信息了 // 将 outClient 视为 UDP_Putter 就可以转发udp信息了
//direct 和 vless 都实现了 UDP_Putter. //direct 和 vless 的Client 都实现了 UDP_Putter.
// direct 实现了 UDP_Putter (通过 UDP_Pipe和 RelayUDP_to_Direct函数), 所以目前 socks5直接转发udp到direct 的功能 已经实现。 // direct 通过 UDP_Pipe和 RelayUDP_to_Direct函数 实现了 UDP_Putter
// 我在 vless 的client 的 UserConn 中实现了 UDP_Putter, 新连接的Handshake过程会在 dialFunc 被调用 时发生 // vless 的client 实现了 UDP_Putter, 新连接的Handshake过程会在 dialFunc 被调用 时发生
if putter := client.(netLayer.UDP_Putter); putter != nil { if putter := client.(netLayer.UDP_Putter); putter != nil {
@@ -818,6 +816,9 @@ afterLocalServerHandshake:
} }
////////////////////////////// 拨号阶段 /////////////////////////////////////
//log.Println("will dial", iics.shouldCloseBaseConnAfterCopyComplete)
dialClient(iics, targetAddr, client, isTlsLazy_clientEnd, wlc, false) dialClient(iics, targetAddr, client, isTlsLazy_clientEnd, wlc, false)
} }
@@ -830,11 +831,19 @@ afterLocalServerHandshake:
func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, client proxy.Client, isTlsLazy_clientEnd bool, wlc io.ReadWriter, noCopy bool) (io.ReadWriter, error) { func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, client proxy.Client, isTlsLazy_clientEnd bool, wlc io.ReadWriter, noCopy bool) (io.ReadWriter, error) {
if iics.shouldCloseBaseConnAfterCopyComplete && !noCopy { if iics.shouldCloseBaseConnAfterCopyComplete && !noCopy {
/*
log.Println("iics.wrappedConn will close after", reflect.TypeOf(iics.wrappedConn))
defer func() {
log.Println("iics.wrappedConn called")
iics.wrappedConn.Close()
log.Println("iics.wrappedConn closed")
}()
*/
defer iics.wrappedConn.Close() defer iics.wrappedConn.Close()
} }
var err error var err error
////////////////////////////// 拨号阶段 /////////////////////////////////////
//先确认拨号地址 //先确认拨号地址
@@ -847,7 +856,7 @@ func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, clien
log.Println("request isn't the appointed domain", targetAddr, uniqueTestDomain) log.Println("request isn't the appointed domain", targetAddr, uniqueTestDomain)
} }
return nil, &utils.NumErr{N: 1, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 1, Prefix: "dialClient err, "}
} }
if utils.CanLogInfo() { if utils.CanLogInfo() {
@@ -890,7 +899,7 @@ func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, clien
log.Println("failed in dial", realTargetAddr.String(), ", Reason: ", err) log.Println("failed in dial", realTargetAddr.String(), ", Reason: ", err)
} }
return nil, &utils.NumErr{N: 2, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 2, Prefix: "dialClient err, "}
} }
//log.Println("dial real addr ok", realTargetAddr) //log.Println("dial real addr ok", realTargetAddr)
@@ -912,7 +921,7 @@ func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, clien
} }
return nil, &utils.NumErr{N: 3, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 3, Prefix: "dialClient err, "}
} else { } else {
clientEndRemoteClientTlsRawReadRecorder = tlsLayer.NewRecorder() clientEndRemoteClientTlsRawReadRecorder = tlsLayer.NewRecorder()
@@ -925,7 +934,7 @@ func dialClient(iics incomingInserverConnState, targetAddr *netLayer.Addr, clien
tlsConn, err := client.GetTLS_Client().Handshake(clientConn) tlsConn, err := client.GetTLS_Client().Handshake(clientConn)
if err != nil { if err != nil {
log.Println("failed in handshake outClient tls", targetAddr.String(), ", Reason: ", err) log.Println("failed in handshake outClient tls", targetAddr.String(), ", Reason: ", err)
return nil, &utils.NumErr{N: 4, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 4, Prefix: "dialClient err, "}
} }
clientConn = tlsConn clientConn = tlsConn
@@ -950,7 +959,7 @@ advLayerStep:
iics.baseLocalConn.Close() iics.baseLocalConn.Close()
} }
return nil, &utils.NumErr{N: 5, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 5, Prefix: "dialClient err, "}
} }
} }
@@ -960,11 +969,14 @@ advLayerStep:
if utils.CanLogErr() { if utils.CanLogErr() {
log.Println("grpc.DialNewSubConn failed,", err) log.Println("grpc.DialNewSubConn failed,", err)
//如果底层tcp连接被关闭了的话错误会是
// rpc error: code = Unavailable desc = connection error: desc = "transport: failed to write client preface: tls: use of closed connection"
} }
if iics.baseLocalConn != nil { if iics.baseLocalConn != nil {
iics.baseLocalConn.Close() iics.baseLocalConn.Close()
} }
return nil, &utils.NumErr{N: 6, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 6, Prefix: "dialClient err, "}
} }
case "ws": case "ws":
@@ -981,7 +993,7 @@ advLayerStep:
if utils.CanLogErr() { if utils.CanLogErr() {
log.Println("err when reading ws early data", e) log.Println("err when reading ws early data", e)
} }
return nil, &utils.NumErr{N: 7, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 7, Prefix: "dialClient err, "}
} }
ed = edBuf[:n] ed = edBuf[:n]
//log.Println("will send early data", n, ed) //log.Println("will send early data", n, ed)
@@ -1007,7 +1019,7 @@ advLayerStep:
log.Println("failed in handshake ws to", targetAddr.String(), ", Reason: ", err) log.Println("failed in handshake ws to", targetAddr.String(), ", Reason: ", err)
} }
return nil, &utils.NumErr{N: 8, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 8, Prefix: "dialClient err, "}
} }
clientConn = wc clientConn = wc
@@ -1022,7 +1034,7 @@ advLayerStep:
log.Println("failed in handshake to", targetAddr.String(), ", Reason: ", err) log.Println("failed in handshake to", targetAddr.String(), ", Reason: ", err)
} }
return nil, &utils.NumErr{N: 9, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 9, Prefix: "dialClient err, "}
} }
//log.Println("all handshake finished") //log.Println("all handshake finished")
@@ -1041,7 +1053,7 @@ advLayerStep:
//必须是 UserClient //必须是 UserClient
if userClient := client.(proxy.UserClient); userClient != nil { if userClient := client.(proxy.UserClient); userClient != nil {
tryTlsLazyRawCopy(false, userClient, nil, nil, wrc, wlc, iics.baseLocalConn, true, clientEndRemoteClientTlsRawReadRecorder) tryTlsLazyRawCopy(false, userClient, nil, nil, wrc, wlc, iics.baseLocalConn, true, clientEndRemoteClientTlsRawReadRecorder)
return nil, &utils.NumErr{N: 11, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 11, Prefix: "dialClient err, "}
} }
} }
@@ -1052,7 +1064,7 @@ advLayerStep:
if userServer, ok := iics.inServer.(proxy.UserServer); ok { if userServer, ok := iics.inServer.(proxy.UserServer); ok {
tryTlsLazyRawCopy(false, nil, userServer, nil, wrc, wlc, iics.baseLocalConn, false, iics.inServerTlsRawReadRecorder) tryTlsLazyRawCopy(false, nil, userServer, nil, wrc, wlc, iics.baseLocalConn, false, iics.inServerTlsRawReadRecorder)
return nil, &utils.NumErr{N: 12, Prefix: "dialClient err, "} return nil, utils.NumErr{N: 12, Prefix: "dialClient err, "}
} }
} }

View File

@@ -29,7 +29,7 @@ func Client_EstablishUDPAssociate(conn net.Conn) (port int, err error) {
return return
} }
if n != 2 || ba[0] != Version5 || ba[1] != 0 { if n != 2 || ba[0] != Version5 || ba[1] != 0 {
return 0, &utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 1} return 0, utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 1}
} }
//请求udp associate 阶段 //请求udp associate 阶段
@@ -45,6 +45,8 @@ func Client_EstablishUDPAssociate(conn net.Conn) (port int, err error) {
ba[8] = 0 //port ba[8] = 0 //port
ba[9] = 0 //port ba[9] = 0 //port
// 按理说要告诉服务端我们要用到的ip和端口但是我们不知道所以全填零 // 按理说要告诉服务端我们要用到的ip和端口但是我们不知道所以全填零
// 在内网中的话我们是可以知道的但是因为内网很安全所以无所谓在NAT中我们肯定是不知道的。
// 如果是在纯外网中则是可以知道的但是为啥非要socks5这么不安全的协议呢所以还是不予考虑。
_, err = conn.Write(ba[:10]) _, err = conn.Write(ba[:10])
if err != nil { if err != nil {
@@ -56,7 +58,7 @@ func Client_EstablishUDPAssociate(conn net.Conn) (port int, err error) {
return return
} }
if n != 10 || ba[0] != Version5 || ba[1] != 0 || ba[2] != 0 || ba[3] != 1 || ba[4] != 0 || ba[5] != 0 || ba[6] != 0 || ba[7] != 0 { if n != 10 || ba[0] != Version5 || ba[1] != 0 || ba[2] != 0 || ba[3] != 1 || ba[4] != 0 || ba[5] != 0 || ba[6] != 0 || ba[7] != 0 {
return 0, &utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 2} return 0, utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 2}
} }
port = int(ba[8])<<8 | int(ba[9]) port = int(ba[8])<<8 | int(ba[9])
@@ -126,7 +128,7 @@ func Client_ReadUDPResponse(udpConn *net.UDPConn, supposedServerAddr *net.UDPAdd
return return
} }
if buf[0] != 0 || buf[1] != 0 || buf[2] != 0 { if buf[0] != 0 || buf[1] != 0 || buf[2] != 0 {
e = &utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 1} e = utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 1}
return return
} }
atype := buf[3] atype := buf[3]
@@ -149,7 +151,7 @@ func Client_ReadUDPResponse(udpConn *net.UDPConn, supposedServerAddr *net.UDPAdd
target.Name = string(nameBuf) target.Name = string(nameBuf)
default: default:
e = &utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 2} e = utils.NumErr{Prefix: "EstablishUDPAssociate,protocol err", N: 2}
return return
} }

View File

@@ -164,7 +164,7 @@ func (s *Server) Handshake(underlay net.Conn) (io.ReadWriter, *netLayer.Addr, er
Network: "udp", Network: "udp",
} }
//这里为了解析域名, 就用了 netLayer.Addr 作为中介的方式 //这里为了解析域名, 就用了 netLayer.Addr 作为中介的方式
uc := &UDPConn{ uc := &UDPConn{
clientSupposedAddr: clientFutureAddr.ToUDPAddr(), clientSupposedAddr: clientFutureAddr.ToUDPAddr(),
UDPConn: udpRC, UDPConn: udpRC,
@@ -243,6 +243,7 @@ func (u *UDPConn) StartPushResponse(udpPutter netLayer.UDP_Putter) {
// 监听 与客户端的udp连接 (u.UDPConn);循环查看客户端发来的请求信息; // 监听 与客户端的udp连接 (u.UDPConn);循环查看客户端发来的请求信息;
// 然后将该请求 用 udpPutter.WriteUDPRequest 发送给 udpPutter // 然后将该请求 用 udpPutter.WriteUDPRequest 发送给 udpPutter
// 至于fullcone与否它是不管的。 // 至于fullcone与否它是不管的。
// 如果客户端一开始没有指明自己连接本服务端的ip和端口, 则将第一个发来的正确的socks5请求视为该客户端,并记录。
func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(targetAddr *netLayer.Addr) (io.ReadWriter, error)) { func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(targetAddr *netLayer.Addr) (io.ReadWriter, error)) {
var clientSupposedAddrIsNothing bool var clientSupposedAddrIsNothing bool
@@ -269,11 +270,14 @@ func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(
continue continue
} }
if !clientSupposedAddrIsNothing && (!addr.IP.Equal(u.clientSupposedAddr.IP) || addr.Port != u.clientSupposedAddr.Port) { if !clientSupposedAddrIsNothing {
//just random attack message. if !addr.IP.Equal(u.clientSupposedAddr.IP) || addr.Port != u.clientSupposedAddr.Port {
continue
//just random attack message.
continue
}
} }
atyp := bs[3] atyp := bs[3]
@@ -322,7 +326,8 @@ func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(
newStart := off + l newStart := off + l
thisaddr := &netLayer.Addr{ //为了解析域名, 我们用 netLayer.Addr 作为中介.
requestAddr := &netLayer.Addr{
IP: theIP, IP: theIP,
Name: theName, Name: theName,
Port: thePort, Port: thePort,
@@ -336,7 +341,7 @@ func (u *UDPConn) StartReadRequest(udpPutter netLayer.UDP_Putter, dialFunc func(
//log.Println("socks5 server,StartReadRequest, got msg", thisaddr, string(bs[newStart:n])) //log.Println("socks5 server,StartReadRequest, got msg", thisaddr, string(bs[newStart:n]))
udpPutter.WriteUDPRequest(thisaddr.ToUDPAddr(), bs[newStart:n], dialFunc) udpPutter.WriteUDPRequest(requestAddr.ToUDPAddr(), bs[newStart:n], dialFunc)
} }
} }

View File

@@ -12,7 +12,7 @@ type NumErr struct {
Prefix string Prefix string
} }
func (ne *NumErr) Error() string { func (ne NumErr) Error() string {
return ne.Prefix + strconv.Itoa(ne.N) return ne.Prefix + strconv.Itoa(ne.N)
} }
@@ -23,57 +23,51 @@ type ErrFirstBuffer struct {
First *bytes.Buffer First *bytes.Buffer
} }
func (ef *ErrFirstBuffer) Unwarp() error { func (ef ErrFirstBuffer) Unwarp() error {
return ef.Err return ef.Err
} }
func (ef *ErrFirstBuffer) Error() string { func (ef ErrFirstBuffer) Error() string {
return ef.Err.Error() return ef.Err.Error()
} }
func NewErr(desc string, e error) *ErrInErr { // 返回结构体,而不是指针, 这样可以避免内存逃逸到堆
return &ErrInErr{ func NewErr(desc string, e error) ErrInErr {
return ErrInErr{
ErrDesc: desc, ErrDesc: desc,
ErrDetail: e, ErrDetail: e,
} }
} }
func NewDataErr(desc string, e error, data interface{}) *ErrInErr { // 返回结构体,而不是指针, 这样可以避免内存逃逸到堆
return &ErrInErr{ func NewDataErr(desc string, e error, data interface{}) ErrInErr {
return ErrInErr{
ErrDesc: desc, ErrDesc: desc,
ErrDetail: e, ErrDetail: e,
Data: data, Data: data,
} }
} }
// ErrInErr 很适合一个err包含另一个err并且提供附带数据的情况 // ErrInErr 很适合一个err包含另一个err并且提供附带数据的情况.
type ErrInErr struct { type ErrInErr struct {
ErrDesc string ErrDesc string
ErrDetail error ErrDetail error
Data any Data any
cachedStr string
} }
func (e *ErrInErr) Error() string { func (e ErrInErr) Error() string {
return e.String() return e.String()
} }
func (e *ErrInErr) Unwarp() error { func (e ErrInErr) Unwarp() error {
return e.ErrDetail return e.ErrDetail
} }
func (e *ErrInErr) String() string { func (e ErrInErr) String() string {
if e.cachedStr == "" {
e.cachedStr = e.string()
}
return e.cachedStr
}
func (e *ErrInErr) string() string {
if e.Data != nil { if e.Data != nil {
if e.ErrDetail != nil { if e.ErrDetail != nil {