我现在基于nps这个项目二次开发了下，
主要改动是丢弃客户端信息的文件存储，客户端连接后就直接存在内存里，
然后socks5反向代理只监听一个端口，通过代理账户名来对应到使用某个客户端作为出口
下面是我改动的文件



-----------------------------------------改动后的bridge.go---------------------------------------------
package bridge

import (
  //"crypto/tls"
  //_ "crypto/tls"
  "hzserver/lib/nps_mux"
  "encoding/binary"
  "errors"
  "fmt"
  "net"
  "os"
  "strconv"
  "strings"
  "sync"
  "time"

  "hzserver/lib/common"
  "hzserver/lib/conn"
  "hzserver/lib/crypt"

  "ehang.io/nps/lib/file"
  "ehang.io/nps/lib/version"

  "hzserver/server/connection"
  "io"
  "hzserver/server/tool"

  "github.com/astaxie/beego"
  "github.com/astaxie/beego/logs"

    "runtime"
    "math/bits"

  //"sync/atomic"
  //"unsafe"
)







type ShardedMap struct {
    shards    []sync.Map
    shardMask uint32
}

func NewShardedMap() *ShardedMap {
    // 设置分片数为 CPU 核心数的 4 倍
    shardCount := runtime.NumCPU() * 4
    // 确保分片数是 2 的幂
    shardCount = 1 << (bits.Len32(uint32(shardCount - 1)))

  logs.Info("shardCount:",shardCount)

    return &ShardedMap{
        shards:    make([]sync.Map, shardCount),
        shardMask: uint32(shardCount - 1),
    }
}

func (m *ShardedMap) Load(key int) (interface{}, bool) {
    shard := &m.shards[uint32(key)&m.shardMask]
    return shard.Load(key)
}

func (m *ShardedMap) Store(key int, value interface{}) {
    shard := &m.shards[uint32(key)&m.shardMask]
    shard.Store(key, value)
}

func (m *ShardedMap) Delete(key int) {
    shard := &m.shards[uint32(key)&m.shardMask]
    shard.Delete(key)
}

func (m *ShardedMap) Range(f func(key, value interface{}) bool) {
    for i := 0; i < len(m.shards); i++ {
        m.shards[i].Range(func(key, value interface{}) bool {
            return f(key, value)
        })
    }
}

// 添加 LoadOrStore 方法
func (m *ShardedMap) LoadOrStore(key int, value interface{}) (actual interface{}, loaded bool) {
    shard := &m.shards[uint32(key)&m.shardMask]
    return shard.LoadOrStore(key, value)
}








var ServerTlsEnable bool = false

type Client struct {
  tunnel    *nps_mux.Mux
  signal    *conn.Conn
  file      *nps_mux.Mux
  Version   string
  retryTime int // it will be add 1 when ping not ok until to 3 will close the client
}

func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
  return &Client{
    signal:  s,
    tunnel:  t,
    file:    f,
    Version: vs,
  }
}

type Bridge struct {
  TunnelPort     int //通信隧道端口
  Client         *ShardedMap
  Register       sync.Map
  tunnelType     string //bridge type kcp or tcp
  OpenTask       chan *file.Tunnel
  CloseTask      chan *file.Tunnel
  CloseClient    chan int
  SecretChan     chan *conn.Secret
  ipVerify       bool
  runList        sync.Map //map[int]interface{}
  disconnectTime int
}

func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
  //logs.Info("NewTunnel",tunnelPort)
  return &Bridge{
    TunnelPort:     tunnelPort,
    tunnelType:     tunnelType,
    OpenTask:       make(chan *file.Tunnel),
    CloseTask:      make(chan *file.Tunnel),
    CloseClient:    make(chan int),
    SecretChan:     make(chan *conn.Secret),
    ipVerify:       ipVerify,
    runList:        runList,
    disconnectTime: disconnectTime,
    Client:         NewShardedMap(),
  }
}

func (s *Bridge) StartTunnel() error {
  go s.ping()


    go func() {
      listener, err := connection.GetBridgeListener(s.tunnelType)
      if err != nil {
        logs.Error(err)
        os.Exit(0)
        return
      }
      conn.Accept(listener, func(c net.Conn) {
        s.cliProcess(conn.NewConn(c))
      })
    }()

  return nil
}

// get health information form client
func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) {
  for {
    if _, _, err := c.GetHealthInfo(); err != nil {
      break
    } 
    /*
    else if !status { //the status is true , return target to the targetArr
      file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
        v := value.(*file.Tunnel)
        if v.Client.Id == id && v.Mode == "tcp" && strings.Contains(v.Target.TargetStr, info) {
          v.Lock()
          if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
            v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
          }
          v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
          if v.HealthRemoveArr == nil {
            v.HealthRemoveArr = make([]string, 0)
          }
          v.HealthRemoveArr = append(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
      file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
        v := value.(*file.Host)
        if v.Client.Id == id && strings.Contains(v.Target.TargetStr, info) {
          v.Lock()
          if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
            v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
          }
          v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
          if v.HealthRemoveArr == nil {
            v.HealthRemoveArr = make([]string, 0)
          }
          v.HealthRemoveArr = append(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
    } else { //the status is false,remove target from the targetArr
      file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
        v := value.(*file.Tunnel)
        if v.Client.Id == id && v.Mode == "tcp" && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
          v.Lock()
          v.Target.TargetArr = append(v.Target.TargetArr, info)
          v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })

      file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
        v := value.(*file.Host)
        if v.Client.Id == id && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
          v.Lock()
          v.Target.TargetArr = append(v.Target.TargetArr, info)
          v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
    }

    */
  }
  s.DelClient(id)
}

// 验证失败，返回错误验证flag，并且关闭连接
func (s *Bridge) verifyError(c *conn.Conn) {
  c.Write([]byte(common.VERIFY_EER))
}

func (s *Bridge) verifySuccess(c *conn.Conn) {
  c.Write([]byte(common.VERIFY_SUCCESS))
}

func (s *Bridge) cliProcess(c *conn.Conn) {
  //read test flag
  if _, err := c.GetShortContent(3); err != nil {
    logs.Info("The client %s connect error", c.Conn.RemoteAddr(), err.Error())
    return
  }
  //version check
  if b, err := c.GetShortLenContent(); err != nil || string(b) != version.GetVersion() {
    //logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
    //c.Close()
    //return
  }
  //version get
  var vs []byte
  var err error
  if vs, err = c.GetShortLenContent(); err != nil {
    logs.Info("get client %s version error", err.Error())
    c.Close()
    return
  }
  //write server version to client
  c.Write([]byte(crypt.Md5(version.GetVersion())))
  c.SetReadDeadlineBySecond(5)

  //var buf []byte
  //get vKey from client


    // 读取 ID 长度
    lenBuf := make([]byte, 1)
    if _, err := c.Read(lenBuf); err != nil {
        logs.Error("Failed to read ID length: %v", err)
        c.Close()
        return
    }
    idLen := int(lenBuf[0])

    // 读取 ID
    idBuf := make([]byte, idLen)
    if _, err := io.ReadFull(c, idBuf); err != nil {
        logs.Error("Failed to read ID: %v", err)
        c.Close()
        return
    }
    vKey_ := strings.Split(string(idBuf),":")

  if len(vKey_) != 2 {
    logs.Error("vkey error1, failed to match the key successfully",vKey_)
    c.Close()
    return
  }

  id,err:=strconv.Atoi(vKey_[1])
  if err!=nil{
    logs.Error("vkey error2, failed to match the key successfully",vKey_)
    c.Close()
    return
  }
  vKey:=vKey_[0]


  //idManager := common.GetIDManager()
  //id := vKey

  //logs.Info("vkey:", vKey, "id:", id)

  //id, exists := idManager.GetIDByVkey(vkey)
  //vkey, exists := idManager.GetVkeyByID(id)

  /*
  id, err := file.GetDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())

  if err != nil {
    logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
    s.verifyError(c)
    return
  } else {
    s.verifySuccess(c)
  }
  */
  s.verifySuccess(c)

  if flag, err := c.ReadFlag(); err == nil {
    s.typeDeal(flag, c, id, string(vs),vKey)
  } else {
    logs.Warn(err, flag)
  }
  return
}

func (s *Bridge) DelClient(id int) {
  if v, ok := s.Client.Load(id); ok {
    if v.(*Client).signal != nil {
      v.(*Client).signal.Close()
    }
    s.Client.Delete(id)

    //common.GetIDManager().ReleaseID(id)
    /*
    if file.GetDb().IsPubClient(id) {
      return
    }

    if c, err := file.GetDb().GetClient(id); err == nil {
      s.CloseClient <- c.Id
    }
    */
  }
}

// use different
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs,vKey string) {

  //isPub := file.GetDb().IsPubClient(id)
  isPub:=false


  switch typeVal {
  case common.WORK_MAIN:
    if isPub {
      c.Close()
      return
    }
    tcpConn, ok := c.Conn.(*net.TCPConn)
    if ok {
      // add tcp keep alive option for signal connection
      _ = tcpConn.SetKeepAlive(true)
      _ = tcpConn.SetKeepAlivePeriod(5 * time.Second)
    }
    //the vKey connect by another ,close the client of before
    if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok {
      if v.(*Client).signal != nil {
        v.(*Client).signal.WriteClose()
      }
      v.(*Client).signal = c
      v.(*Client).Version = vs
    }

    common.Vm.Set(id, vKey+" "+c.Conn.RemoteAddr().String())

    go s.GetHealthFromClient(id, c)
    logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
    
  
  
  case common.WORK_CHAN:
    muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
    if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
      v.(*Client).tunnel = muxConn
    }
  case common.WORK_CONFIG:
    client, err := file.GetDb().GetClient(id)
    if err != nil || (!isPub && !client.ConfigConnAllow) {
      c.Close()
      return
    }
    binary.Write(c, binary.LittleEndian, isPub)
    go s.getConfig(c, isPub, client)
  case common.WORK_REGISTER:
    go s.register(c)
  case common.WORK_SECRET:
    if b, err := c.GetShortContent(32); err == nil {
      s.SecretChan <- conn.NewSecret(string(b), c)
    } else {
      logs.Error("secret error, failed to match the key successfully")
    }
  case common.WORK_FILE:
    muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
    if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
      v.(*Client).file = muxConn
    }
  case common.WORK_P2P:
    //read md5 secret
    if b, err := c.GetShortContent(32); err != nil {
      logs.Error("p2p error,", err.Error())
    } else if t := file.GetDb().GetTaskByMd5Password(string(b)); t == nil {
      logs.Error("p2p error, failed to match the key successfully")
    } else {
      if v, ok := s.Client.Load(t.Client.Id); !ok {
        return
      } else {
        //向密钥对应的客户端发送与服务端udp建立连接信息，地址，密钥
        v.(*Client).signal.Write([]byte(common.NEW_UDP_CONN))
        svrAddr := beego.AppConfig.String("p2p_ip") + ":" + beego.AppConfig.String("p2p_port")
        if err != nil {
          logs.Warn("get local udp addr error")
          return
        }
        v.(*Client).signal.WriteLenContent([]byte(svrAddr))
        v.(*Client).signal.WriteLenContent(b)
        //向该请求者发送建立连接请求,服务器地址
        c.WriteLenContent([]byte(svrAddr))
      }
    }
    


  }
  c.SetAlive(s.tunnelType)
  return
}

// register ip
func (s *Bridge) register(c *conn.Conn) {
  var hour int32
  if err := binary.Read(c, binary.LittleEndian, &hour); err == nil {
    s.Register.Store(common.GetIpByAddr(c.Conn.RemoteAddr().String()), time.Now().Add(time.Hour*time.Duration(hour)))
  }
}

func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
  //if the proxy type is local
  /*
  if link.LocalProxy {
    target, err = net.Dial("tcp", link.Host)
    return
  }
  */
  if v, ok := s.Client.Load(clientId); ok {
    //If ip is restricted to do ip verification
    /*
    if s.ipVerify {
      ip := common.GetIpByAddr(link.RemoteAddr)
      if v, ok := s.Register.Load(ip); !ok {
        return nil, errors.New(fmt.Sprintf("The ip %s is not in the validation list", ip))
      } else {
        if !v.(time.Time).After(time.Now()) {
          return nil, errors.New(fmt.Sprintf("The validity of the ip %s has expired", ip))
        }
      }
    }
      */


    var tunnel *nps_mux.Mux
    /*
    if t != nil && t.Mode == "file" {
      tunnel = v.(*Client).file
    } else {
      tunnel = v.(*Client).tunnel
    }
      */
    tunnel = v.(*Client).tunnel

    if tunnel == nil {
      err = errors.New("the client connect error")
      return
    }


    if target, err = tunnel.NewConn(); err != nil {
      return
    }
    /*
    if t != nil && t.Mode == "file" {
      //TODO if t.mode is file ,not use crypt or compress
      link.Crypt = false
      link.Compress = false
      return
    }
      */
    if _, err = conn.NewConn(target).SendInfo(link, ""); err != nil {
      logs.Info("new connect error ,the target %s refuse to connect", link.Host)
      return
    }
  } else {
    err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
  }
  return
}

func (s *Bridge) ping() {
  ticker := time.NewTicker(time.Second * 5)
  defer ticker.Stop()
  for {
    select {
    case <-ticker.C:
      arr := make([]int, 0)
      s.Client.Range(func(key, value interface{}) bool {
        v := value.(*Client)
        if v.tunnel == nil || v.signal == nil {
          v.retryTime += 1
          if v.retryTime >= 3 {
            arr = append(arr, key.(int))
          }
          return true
        }
        if v.tunnel.IsClose {
          arr = append(arr, key.(int))
        }
        return true
      })
      for _, v := range arr {
        logs.Info("the client %d closed", v)
        s.DelClient(v)
      }
    }
  }
}

// get config and add task from client config
func (s *Bridge) getConfig(c *conn.Conn, isPub bool, client *file.Client) {
  var fail bool
loop:
  for {
    flag, err := c.ReadFlag()
    if err != nil {
      break
    }
    switch flag {
    case common.WORK_STATUS:
      if b, err := c.GetShortContent(32); err != nil {
        break loop
      } else {
        var str string
        id, err := file.GetDb().GetClientIdByVkey(string(b))
        if err != nil {
          break loop
        }
        file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
          v := value.(*file.Host)
          if v.Client.Id == id {
            str += v.Remark + common.CONN_DATA_SEQ
          }
          return true
        })
        file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
          v := value.(*file.Tunnel)
          //if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
          if _, ok := s.runList.Load(v.Id); ok && v.Client.Id == id {
            str += v.Remark + common.CONN_DATA_SEQ
          }
          return true
        })
        binary.Write(c, binary.LittleEndian, int32(len([]byte(str))))
        binary.Write(c, binary.LittleEndian, []byte(str))
      }
    case common.NEW_CONF:
      var err error
      if client, err = c.GetConfigInfo(); err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      } else {
        if err = file.GetDb().NewClient(client); err != nil {
          fail = true
          c.WriteAddFail()
          break loop
        }
        c.WriteAddOk()
        c.Write([]byte(client.VerifyKey))
        s.Client.Store(client.Id, NewClient(nil, nil, nil, ""))
      }
    case common.NEW_HOST:
      h, err := c.GetHostInfo()
      if err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      }
      h.Client = client
      if h.Location == "" {
        h.Location = "/"
      }
      if !client.HasHost(h) {
        if file.GetDb().IsHostExist(h) {
          fail = true
          c.WriteAddFail()
          break loop
        } else {
          file.GetDb().NewHost(h)
          c.WriteAddOk()
        }
      } else {
        c.WriteAddOk()
      }
    case common.NEW_TASK:
      if t, err := c.GetTaskInfo(); err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      } else {
        ports := common.GetPorts(t.Ports)
        targets := common.GetPorts(t.Target.TargetStr)
        if len(ports) > 1 && (t.Mode == "tcp" || t.Mode == "udp") && (len(ports) != len(targets)) {
          fail = true
          c.WriteAddFail()
          break loop
        } else if t.Mode == "secret" || t.Mode == "p2p" {
          ports = append(ports, 0)
        }
        if len(ports) == 0 {
          fail = true
          c.WriteAddFail()
          break loop
        }
        for i := 0; i < len(ports); i++ {
          tl := new(file.Tunnel)
          tl.Mode = t.Mode
          tl.Port = ports[i]
          tl.ServerIp = t.ServerIp
          if len(ports) == 1 {
            tl.Target = t.Target
            tl.Remark = t.Remark
          } else {
            tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
            tl.Target = new(file.Target)
            if t.TargetAddr != "" {
              tl.Target.TargetStr = t.TargetAddr + ":" + strconv.Itoa(targets[i])
            } else {
              tl.Target.TargetStr = strconv.Itoa(targets[i])
            }
          }
          tl.Id = int(file.GetDb().JsonDb.GetTaskId())
          tl.Status = true
          tl.Flow = new(file.Flow)
          tl.NoStore = true
          tl.Client = client
          tl.Password = t.Password
          tl.LocalPath = t.LocalPath
          tl.StripPre = t.StripPre
          tl.MultiAccount = t.MultiAccount
          if !client.HasTunnel(tl) {
            if err := file.GetDb().NewTask(tl); err != nil {
              logs.Notice("Add task error ", err.Error())
              fail = true
              c.WriteAddFail()
              break loop
            }
            if b := tool.TestServerPort(tl.Port, tl.Mode); !b && t.Mode != "secret" && t.Mode != "p2p" {
              fail = true
              c.WriteAddFail()
              break loop
            } else {
              s.OpenTask <- tl
            }
          }
          c.WriteAddOk()
        }
      }
    }
  }
  if fail && client != nil {
    s.DelClient(client.Id)
  }
  c.Close()
}



---------------------------------原版本的bridge.go----------------------------------------------------
package bridge

import (
  "crypto/tls"
  _ "crypto/tls"
  "ehang.io/nps/lib/nps_mux"
  "encoding/binary"
  "errors"
  "fmt"
  "net"
  "os"
  "strconv"
  "strings"
  "sync"
  "time"

  "ehang.io/nps/lib/common"
  "ehang.io/nps/lib/conn"
  "ehang.io/nps/lib/crypt"
  "ehang.io/nps/lib/file"
  "ehang.io/nps/lib/version"
  "ehang.io/nps/server/connection"
  "ehang.io/nps/server/tool"
  "github.com/astaxie/beego"
  "github.com/astaxie/beego/logs"
)

var ServerTlsEnable bool = false

type Client struct {
  tunnel    *nps_mux.Mux
  signal    *conn.Conn
  file      *nps_mux.Mux
  Version   string
  retryTime int // it will be add 1 when ping not ok until to 3 will close the client
}

func NewClient(t, f *nps_mux.Mux, s *conn.Conn, vs string) *Client {
  return &Client{
    signal:  s,
    tunnel:  t,
    file:    f,
    Version: vs,
  }
}

type Bridge struct {
  TunnelPort     int //通信隧道端口
  Client         sync.Map
  Register       sync.Map
  tunnelType     string //bridge type kcp or tcp
  OpenTask       chan *file.Tunnel
  CloseTask      chan *file.Tunnel
  CloseClient    chan int
  SecretChan     chan *conn.Secret
  ipVerify       bool
  runList        sync.Map //map[int]interface{}
  disconnectTime int
}

func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList sync.Map, disconnectTime int) *Bridge {
  return &Bridge{
    TunnelPort:     tunnelPort,
    tunnelType:     tunnelType,
    OpenTask:       make(chan *file.Tunnel),
    CloseTask:      make(chan *file.Tunnel),
    CloseClient:    make(chan int),
    SecretChan:     make(chan *conn.Secret),
    ipVerify:       ipVerify,
    runList:        runList,
    disconnectTime: disconnectTime,
  }
}

func (s *Bridge) StartTunnel() error {
  go s.ping()
  if s.tunnelType == "kcp" {
    logs.Info("server start, the bridge type is %s, the bridge port is %d", s.tunnelType, s.TunnelPort)
    return conn.NewKcpListenerAndProcess(beego.AppConfig.String("bridge_ip")+":"+beego.AppConfig.String("bridge_port"), func(c net.Conn) {
      s.cliProcess(conn.NewConn(c))
    })
  } else {

    go func() {
      listener, err := connection.GetBridgeListener(s.tunnelType)
      if err != nil {
        logs.Error(err)
        os.Exit(0)
        return
      }
      conn.Accept(listener, func(c net.Conn) {
        s.cliProcess(conn.NewConn(c))
      })
    }()

    // tls
    if ServerTlsEnable {
      go func() {
        // 监听TLS 端口
        tlsBridgePort := beego.AppConfig.DefaultInt("tls_bridge_port", 8025)

        logs.Info("tls server start, the bridge type is %s, the tls bridge port is %d", "tcp", tlsBridgePort)
        tlsListener, tlsErr := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(beego.AppConfig.String("bridge_ip")), tlsBridgePort, ""})
        if tlsErr != nil {
          logs.Error(tlsErr)
          os.Exit(0)
          return
        }
        conn.Accept(tlsListener, func(c net.Conn) {
          s.cliProcess(conn.NewConn(tls.Server(c, &tls.Config{Certificates: []tls.Certificate{crypt.GetCert()}})))
        })
      }()
    }
  }
  return nil
}

// get health information form client
func (s *Bridge) GetHealthFromClient(id int, c *conn.Conn) {
  for {
    if info, status, err := c.GetHealthInfo(); err != nil {
      break
    } else if !status { //the status is true , return target to the targetArr
      file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
        v := value.(*file.Tunnel)
        if v.Client.Id == id && v.Mode == "tcp" && strings.Contains(v.Target.TargetStr, info) {
          v.Lock()
          if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
            v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
          }
          v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
          if v.HealthRemoveArr == nil {
            v.HealthRemoveArr = make([]string, 0)
          }
          v.HealthRemoveArr = append(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
      file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
        v := value.(*file.Host)
        if v.Client.Id == id && strings.Contains(v.Target.TargetStr, info) {
          v.Lock()
          if v.Target.TargetArr == nil || (len(v.Target.TargetArr) == 0 && len(v.HealthRemoveArr) == 0) {
            v.Target.TargetArr = common.TrimArr(strings.Split(v.Target.TargetStr, "\n"))
          }
          v.Target.TargetArr = common.RemoveArrVal(v.Target.TargetArr, info)
          if v.HealthRemoveArr == nil {
            v.HealthRemoveArr = make([]string, 0)
          }
          v.HealthRemoveArr = append(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
    } else { //the status is false,remove target from the targetArr
      file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
        v := value.(*file.Tunnel)
        if v.Client.Id == id && v.Mode == "tcp" && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
          v.Lock()
          v.Target.TargetArr = append(v.Target.TargetArr, info)
          v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })

      file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
        v := value.(*file.Host)
        if v.Client.Id == id && common.IsArrContains(v.HealthRemoveArr, info) && !common.IsArrContains(v.Target.TargetArr, info) {
          v.Lock()
          v.Target.TargetArr = append(v.Target.TargetArr, info)
          v.HealthRemoveArr = common.RemoveArrVal(v.HealthRemoveArr, info)
          v.Unlock()
        }
        return true
      })
    }
  }
  s.DelClient(id)
}

// 验证失败，返回错误验证flag，并且关闭连接
func (s *Bridge) verifyError(c *conn.Conn) {
  c.Write([]byte(common.VERIFY_EER))
}

func (s *Bridge) verifySuccess(c *conn.Conn) {
  c.Write([]byte(common.VERIFY_SUCCESS))
}

func (s *Bridge) cliProcess(c *conn.Conn) {
  //read test flag
  if _, err := c.GetShortContent(3); err != nil {
    logs.Info("The client %s connect error", c.Conn.RemoteAddr(), err.Error())
    return
  }
  //version check
  if b, err := c.GetShortLenContent(); err != nil || string(b) != version.GetVersion() {
    //logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
    //c.Close()
    //return
  }
  //version get
  var vs []byte
  var err error
  if vs, err = c.GetShortLenContent(); err != nil {
    logs.Info("get client %s version error", err.Error())
    c.Close()
    return
  }
  //write server version to client
  c.Write([]byte(crypt.Md5(version.GetVersion())))
  c.SetReadDeadlineBySecond(5)
  var buf []byte
  //get vKey from client
  if buf, err = c.GetShortContent(32); err != nil {
    c.Close()
    return
  }
  //verify
  id, err := file.GetDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
  if err != nil {
    logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
    s.verifyError(c)
    return
  } else {
    s.verifySuccess(c)
  }
  if flag, err := c.ReadFlag(); err == nil {
    s.typeDeal(flag, c, id, string(vs))
  } else {
    logs.Warn(err, flag)
  }
  return
}

func (s *Bridge) DelClient(id int) {
  if v, ok := s.Client.Load(id); ok {
    if v.(*Client).signal != nil {
      v.(*Client).signal.Close()
    }
    s.Client.Delete(id)
    if file.GetDb().IsPubClient(id) {
      return
    }
    if c, err := file.GetDb().GetClient(id); err == nil {
      s.CloseClient <- c.Id
    }
  }
}

// use different
func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int, vs string) {
  isPub := file.GetDb().IsPubClient(id)
  switch typeVal {
  case common.WORK_MAIN:
    if isPub {
      c.Close()
      return
    }
    tcpConn, ok := c.Conn.(*net.TCPConn)
    if ok {
      // add tcp keep alive option for signal connection
      _ = tcpConn.SetKeepAlive(true)
      _ = tcpConn.SetKeepAlivePeriod(5 * time.Second)
    }
    //the vKey connect by another ,close the client of before
    if v, ok := s.Client.LoadOrStore(id, NewClient(nil, nil, c, vs)); ok {
      if v.(*Client).signal != nil {
        v.(*Client).signal.WriteClose()
      }
      v.(*Client).signal = c
      v.(*Client).Version = vs
    }
    go s.GetHealthFromClient(id, c)
    logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
  case common.WORK_CHAN:
    muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
    if v, ok := s.Client.LoadOrStore(id, NewClient(muxConn, nil, nil, vs)); ok {
      v.(*Client).tunnel = muxConn
    }
  case common.WORK_CONFIG:
    client, err := file.GetDb().GetClient(id)
    if err != nil || (!isPub && !client.ConfigConnAllow) {
      c.Close()
      return
    }
    binary.Write(c, binary.LittleEndian, isPub)
    go s.getConfig(c, isPub, client)
  case common.WORK_REGISTER:
    go s.register(c)
  case common.WORK_SECRET:
    if b, err := c.GetShortContent(32); err == nil {
      s.SecretChan <- conn.NewSecret(string(b), c)
    } else {
      logs.Error("secret error, failed to match the key successfully")
    }
  case common.WORK_FILE:
    muxConn := nps_mux.NewMux(c.Conn, s.tunnelType, s.disconnectTime)
    if v, ok := s.Client.LoadOrStore(id, NewClient(nil, muxConn, nil, vs)); ok {
      v.(*Client).file = muxConn
    }
  case common.WORK_P2P:
    //read md5 secret
    if b, err := c.GetShortContent(32); err != nil {
      logs.Error("p2p error,", err.Error())
    } else if t := file.GetDb().GetTaskByMd5Password(string(b)); t == nil {
      logs.Error("p2p error, failed to match the key successfully")
    } else {
      if v, ok := s.Client.Load(t.Client.Id); !ok {
        return
      } else {
        //向密钥对应的客户端发送与服务端udp建立连接信息，地址，密钥
        v.(*Client).signal.Write([]byte(common.NEW_UDP_CONN))
        svrAddr := beego.AppConfig.String("p2p_ip") + ":" + beego.AppConfig.String("p2p_port")
        if err != nil {
          logs.Warn("get local udp addr error")
          return
        }
        v.(*Client).signal.WriteLenContent([]byte(svrAddr))
        v.(*Client).signal.WriteLenContent(b)
        //向该请求者发送建立连接请求,服务器地址
        c.WriteLenContent([]byte(svrAddr))
      }
    }
  }
  c.SetAlive(s.tunnelType)
  return
}

// register ip
func (s *Bridge) register(c *conn.Conn) {
  var hour int32
  if err := binary.Read(c, binary.LittleEndian, &hour); err == nil {
    s.Register.Store(common.GetIpByAddr(c.Conn.RemoteAddr().String()), time.Now().Add(time.Hour*time.Duration(hour)))
  }
}

func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error) {
  //if the proxy type is local
  if link.LocalProxy {
    target, err = net.Dial("tcp", link.Host)
    return
  }
  if v, ok := s.Client.Load(clientId); ok {
    //If ip is restricted to do ip verification
    if s.ipVerify {
      ip := common.GetIpByAddr(link.RemoteAddr)
      if v, ok := s.Register.Load(ip); !ok {
        return nil, errors.New(fmt.Sprintf("The ip %s is not in the validation list", ip))
      } else {
        if !v.(time.Time).After(time.Now()) {
          return nil, errors.New(fmt.Sprintf("The validity of the ip %s has expired", ip))
        }
      }
    }
    var tunnel *nps_mux.Mux
    if t != nil && t.Mode == "file" {
      tunnel = v.(*Client).file
    } else {
      tunnel = v.(*Client).tunnel
    }
    if tunnel == nil {
      err = errors.New("the client connect error")
      return
    }
    if target, err = tunnel.NewConn(); err != nil {
      return
    }
    if t != nil && t.Mode == "file" {
      //TODO if t.mode is file ,not use crypt or compress
      link.Crypt = false
      link.Compress = false
      return
    }
    if _, err = conn.NewConn(target).SendInfo(link, ""); err != nil {
      logs.Info("new connect error ,the target %s refuse to connect", link.Host)
      return
    }
  } else {
    err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
  }
  return
}

func (s *Bridge) ping() {
  ticker := time.NewTicker(time.Second * 5)
  defer ticker.Stop()
  for {
    select {
    case <-ticker.C:
      arr := make([]int, 0)
      s.Client.Range(func(key, value interface{}) bool {
        v := value.(*Client)
        if v.tunnel == nil || v.signal == nil {
          v.retryTime += 1
          if v.retryTime >= 3 {
            arr = append(arr, key.(int))
          }
          return true
        }
        if v.tunnel.IsClose {
          arr = append(arr, key.(int))
        }
        return true
      })
      for _, v := range arr {
        logs.Info("the client %d closed", v)
        s.DelClient(v)
      }
    }
  }
}

// get config and add task from client config
func (s *Bridge) getConfig(c *conn.Conn, isPub bool, client *file.Client) {
  var fail bool
loop:
  for {
    flag, err := c.ReadFlag()
    if err != nil {
      break
    }
    switch flag {
    case common.WORK_STATUS:
      if b, err := c.GetShortContent(32); err != nil {
        break loop
      } else {
        var str string
        id, err := file.GetDb().GetClientIdByVkey(string(b))
        if err != nil {
          break loop
        }
        file.GetDb().JsonDb.Hosts.Range(func(key, value interface{}) bool {
          v := value.(*file.Host)
          if v.Client.Id == id {
            str += v.Remark + common.CONN_DATA_SEQ
          }
          return true
        })
        file.GetDb().JsonDb.Tasks.Range(func(key, value interface{}) bool {
          v := value.(*file.Tunnel)
          //if _, ok := s.runList[v.Id]; ok && v.Client.Id == id {
          if _, ok := s.runList.Load(v.Id); ok && v.Client.Id == id {
            str += v.Remark + common.CONN_DATA_SEQ
          }
          return true
        })
        binary.Write(c, binary.LittleEndian, int32(len([]byte(str))))
        binary.Write(c, binary.LittleEndian, []byte(str))
      }
    case common.NEW_CONF:
      var err error
      if client, err = c.GetConfigInfo(); err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      } else {
        if err = file.GetDb().NewClient(client); err != nil {
          fail = true
          c.WriteAddFail()
          break loop
        }
        c.WriteAddOk()
        c.Write([]byte(client.VerifyKey))
        s.Client.Store(client.Id, NewClient(nil, nil, nil, ""))
      }
    case common.NEW_HOST:
      h, err := c.GetHostInfo()
      if err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      }
      h.Client = client
      if h.Location == "" {
        h.Location = "/"
      }
      if !client.HasHost(h) {
        if file.GetDb().IsHostExist(h) {
          fail = true
          c.WriteAddFail()
          break loop
        } else {
          file.GetDb().NewHost(h)
          c.WriteAddOk()
        }
      } else {
        c.WriteAddOk()
      }
    case common.NEW_TASK:
      if t, err := c.GetTaskInfo(); err != nil {
        fail = true
        c.WriteAddFail()
        break loop
      } else {
        ports := common.GetPorts(t.Ports)
        targets := common.GetPorts(t.Target.TargetStr)
        if len(ports) > 1 && (t.Mode == "tcp" || t.Mode == "udp") && (len(ports) != len(targets)) {
          fail = true
          c.WriteAddFail()
          break loop
        } else if t.Mode == "secret" || t.Mode == "p2p" {
          ports = append(ports, 0)
        }
        if len(ports) == 0 {
          fail = true
          c.WriteAddFail()
          break loop
        }
        for i := 0; i < len(ports); i++ {
          tl := new(file.Tunnel)
          tl.Mode = t.Mode
          tl.Port = ports[i]
          tl.ServerIp = t.ServerIp
          if len(ports) == 1 {
            tl.Target = t.Target
            tl.Remark = t.Remark
          } else {
            tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
            tl.Target = new(file.Target)
            if t.TargetAddr != "" {
              tl.Target.TargetStr = t.TargetAddr + ":" + strconv.Itoa(targets[i])
            } else {
              tl.Target.TargetStr = strconv.Itoa(targets[i])
            }
          }
          tl.Id = int(file.GetDb().JsonDb.GetTaskId())
          tl.Status = true
          tl.Flow = new(file.Flow)
          tl.NoStore = true
          tl.Client = client
          tl.Password = t.Password
          tl.LocalPath = t.LocalPath
          tl.StripPre = t.StripPre
          tl.MultiAccount = t.MultiAccount
          if !client.HasTunnel(tl) {
            if err := file.GetDb().NewTask(tl); err != nil {
              logs.Notice("Add task error ", err.Error())
              fail = true
              c.WriteAddFail()
              break loop
            }
            if b := tool.TestServerPort(tl.Port, tl.Mode); !b && t.Mode != "secret" && t.Mode != "p2p" {
              fail = true
              c.WriteAddFail()
              break loop
            } else {
              s.OpenTask <- tl
            }
          }
          c.WriteAddOk()
        }
      }
    }
  }
  if fail && client != nil {
    s.DelClient(client.Id)
  }
  c.Close()
}




----------------------------------------改动后的server/proxy/base.go--------------------------------------------------
package proxy

import (
  "errors"
  "net"
  "net/http"
  "sort"
  "sync"

  "hzserver/bridge"
  "hzserver/lib/common"
  "hzserver/lib/conn"

  "ehang.io/nps/lib/file"
  "github.com/astaxie/beego/logs"
)


type Client struct {
  //Cnf             *Config
  Id              int        //id
  VerifyKey       string     //verify key
  Addr            string     //the ip of client
  Remark          string     //remark
  Status          bool       //is allow connect
  IsConnect       bool       //is the client connect
  RateLimit       int        //rate /kb
  //Flow            *Flow      //flow setting
  //Rate            *rate.Rate //rate limit
  NoStore         bool       //no store to file
  NoDisplay       bool       //no display on web
  MaxConn         int        //the max connection num of client allow
  NowConn         int32      //the connection num of now
  WebUserName     string     //the username of web login
  WebPassword     string     //the password of web login
  ConfigConnAllow bool       //is allow connected by config file
  MaxTunnelNum    int
  Version         string
  BlackIpList     []string
  LastOnlineTime  string
  sync.RWMutex
}

type Service interface {
  Start() error
  Close() error
}

type NetBridge interface {
  SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error)
}

//BaseServer struct
type BaseServer struct {
  id           int
  bridge       NetBridge
  task         *file.Tunnel
  errorContent []byte
  sync.Mutex
}

func NewBaseServer(bridge *bridge.Bridge, task *file.Tunnel) *BaseServer {
  return &BaseServer{
    bridge:       bridge,
    task:         task,
    errorContent: nil,
    Mutex:        sync.Mutex{},
  }
}

//add the flow
func (s *BaseServer) FlowAdd(in, out int64) {
  s.Lock()
  defer s.Unlock()
  s.task.Flow.ExportFlow += out
  s.task.Flow.InletFlow += in
}

//change the flow
func (s *BaseServer) FlowAddHost(host *file.Host, in, out int64) {
  s.Lock()
  defer s.Unlock()
  host.Flow.ExportFlow += out
  host.Flow.InletFlow += in
}

//write fail bytes to the connection
func (s *BaseServer) writeConnFail(c net.Conn) {
  c.Write([]byte(common.ConnectionFailBytes))
  c.Write(s.errorContent)
}

//auth check
func (s *BaseServer) auth(r *http.Request, c *conn.Conn, u, p string) error {
  if u != "" && p != "" && !common.CheckAuth(r, u, p) {
    c.Write([]byte(common.UnauthorizedBytes))
    c.Close()
    return errors.New("401 Unauthorized")
  }
  return nil
}

//check flow limit of the client ,and decrease the allow num of client
/*
func (s *BaseServer) CheckFlowAndConnNum(client *file.Client) error {
  if client.Flow.FlowLimit > 0 && (client.Flow.FlowLimit<<20) < (client.Flow.ExportFlow+client.Flow.InletFlow) {
    return errors.New("Traffic exceeded")
  }
  if !client.GetConn() {
    return errors.New("Connections exceed the current client limit")
  }
  return nil
}
*/


func in(target string, str_array []string) bool {
  sort.Strings(str_array)
  index := sort.SearchStrings(str_array, target)
  if index < len(str_array) && str_array[index] == target {
    return true
  }
  return false
}

//create a new connection and start bytes copying
func (s *BaseServer) DealClient(c *conn.Conn, client *Client, addr string,
  rb []byte, tp string, f func(), flow *file.Flow, localProxy bool, task *file.Tunnel) error {

  /*
  // 判断访问地址是否在全局黑名单内
  if IsGlobalBlackIp(c.RemoteAddr().String()) {
    c.Close()
    return nil
  }

  // 判断访问地址是否在黑名单内
  if common.IsBlackIp(c.RemoteAddr().String(), client.VerifyKey, client.BlackIpList) {
    c.Close()
    return nil
  }

  */


  link := conn.NewLink(tp, addr, false, false, c.Conn.RemoteAddr().String(), localProxy)
  if target, err := s.bridge.SendLinkInfo(client.Id, link, s.task); err != nil {
    logs.Warn("get connection from client id %d  error2 %s", client.Id, err.Error())
    c.Close()
    return err
  } else {
    if f != nil {
      f()
    }
    conn.CopyWaitGroup(target, c.Conn, link.Crypt, link.Compress, nil, flow, true, rb)
  }
  return nil
}

// 判断访问地址是否在全局黑名单内
/*
func IsGlobalBlackIp(ipPort string) bool {
  // 判断访问地址是否在全局黑名单内
  global := file.GetDb().GetGlobal()
  if global != nil {
    ip := common.GetIpByAddr(ipPort)
    if in(ip, global.BlackIpList) {
      logs.Error("IP地址[" + ip + "]在全局黑名单列表内")
      return true
    }
  }

  return false
}
*/
















--------------------------------------原版本的server/proxy/base.go-------------------------------------------------

package proxy

import (
  "errors"
  "net"
  "net/http"
  "sort"
  "sync"

  "ehang.io/nps/bridge"
  "ehang.io/nps/lib/common"
  "ehang.io/nps/lib/conn"
  "ehang.io/nps/lib/file"
  "github.com/astaxie/beego/logs"
)

type Service interface {
  Start() error
  Close() error
}

type NetBridge interface {
  SendLinkInfo(clientId int, link *conn.Link, t *file.Tunnel) (target net.Conn, err error)
}

//BaseServer struct
type BaseServer struct {
  id           int
  bridge       NetBridge
  task         *file.Tunnel
  errorContent []byte
  sync.Mutex
}

func NewBaseServer(bridge *bridge.Bridge, task *file.Tunnel) *BaseServer {
  return &BaseServer{
    bridge:       bridge,
    task:         task,
    errorContent: nil,
    Mutex:        sync.Mutex{},
  }
}

//add the flow
func (s *BaseServer) FlowAdd(in, out int64) {
  s.Lock()
  defer s.Unlock()
  s.task.Flow.ExportFlow += out
  s.task.Flow.InletFlow += in
}

//change the flow
func (s *BaseServer) FlowAddHost(host *file.Host, in, out int64) {
  s.Lock()
  defer s.Unlock()
  host.Flow.ExportFlow += out
  host.Flow.InletFlow += in
}

//write fail bytes to the connection
func (s *BaseServer) writeConnFail(c net.Conn) {
  c.Write([]byte(common.ConnectionFailBytes))
  c.Write(s.errorContent)
}

//auth check
func (s *BaseServer) auth(r *http.Request, c *conn.Conn, u, p string) error {
  if u != "" && p != "" && !common.CheckAuth(r, u, p) {
    c.Write([]byte(common.UnauthorizedBytes))
    c.Close()
    return errors.New("401 Unauthorized")
  }
  return nil
}

//check flow limit of the client ,and decrease the allow num of client
func (s *BaseServer) CheckFlowAndConnNum(client *file.Client) error {
  if client.Flow.FlowLimit > 0 && (client.Flow.FlowLimit<<20) < (client.Flow.ExportFlow+client.Flow.InletFlow) {
    return errors.New("Traffic exceeded")
  }
  if !client.GetConn() {
    return errors.New("Connections exceed the current client limit")
  }
  return nil
}

func in(target string, str_array []string) bool {
  sort.Strings(str_array)
  index := sort.SearchStrings(str_array, target)
  if index < len(str_array) && str_array[index] == target {
    return true
  }
  return false
}

//create a new connection and start bytes copying
func (s *BaseServer) DealClient(c *conn.Conn, client *file.Client, addr string,
  rb []byte, tp string, f func(), flow *file.Flow, localProxy bool, task *file.Tunnel) error {

  // 判断访问地址是否在全局黑名单内
  if IsGlobalBlackIp(c.RemoteAddr().String()) {
    c.Close()
    return nil
  }

  // 判断访问地址是否在黑名单内
  if common.IsBlackIp(c.RemoteAddr().String(), client.VerifyKey, client.BlackIpList) {
    c.Close()
    return nil
  }

  link := conn.NewLink(tp, addr, client.Cnf.Crypt, client.Cnf.Compress, c.Conn.RemoteAddr().String(), localProxy)
  if target, err := s.bridge.SendLinkInfo(client.Id, link, s.task); err != nil {
    logs.Warn("get connection from client id %d  error %s", client.Id, err.Error())
    c.Close()
    return err
  } else {
    if f != nil {
      f()
    }
    conn.CopyWaitGroup(target, c.Conn, link.Crypt, link.Compress, client.Rate, flow, true, rb, task)
  }
  return nil
}

// 判断访问地址是否在全局黑名单内
func IsGlobalBlackIp(ipPort string) bool {
  // 判断访问地址是否在全局黑名单内
  global := file.GetDb().GetGlobal()
  if global != nil {
    ip := common.GetIpByAddr(ipPort)
    if in(ip, global.BlackIpList) {
      logs.Error("IP地址[" + ip + "]在全局黑名单列表内")
      return true
    }
  }

  return false
}
















-------------------------------------改动后的server/proxy/socks5.go---------------------------------------------

package proxy

import (
  "encoding/binary"
  "errors"
  "io"
  "net"
  "strconv"

  "hzserver/lib/common"
  "hzserver/lib/conn"

  //"fmt"
  //"sync"
  "strings"

  "ehang.io/nps/lib/file"
  "github.com/astaxie/beego/logs"
)

const (
  ipV4            = 1
  domainName      = 3
  ipV6            = 4
  connectMethod   = 1
  bindMethod      = 2
  associateMethod = 3
  // The maximum packet size of any udp Associate packet, based on ethernet's max size,
  // minus the IP and UDP headers. IPv4 has a 20 byte header, UDP adds an
  // additional 4 bytes.  This is a total overhead of 24 bytes.  Ethernet's
  // max packet size is 1500 bytes,  1500 - 24 = 1476.
  maxUDPPacketSize = 1476
)

const (
  succeeded uint8 = iota
  serverFailure
  notAllowed
  networkUnreachable
  hostUnreachable
  connectionRefused
  ttlExpired
  commandNotSupported
  addrTypeNotSupported
)

const (
  UserPassAuth    = uint8(2)
  userAuthVersion = uint8(1)
  authSuccess     = uint8(0)
  authFailure     = uint8(1)
)

type Sock5ModeServer struct {
  BaseServer
  listener net.Listener
}

//req
func (s *Sock5ModeServer) handleRequest(c net.Conn,ss *Sock5ModeServer,id int) {
  /*
    The SOCKS request is formed as follows:
    +----+-----+-------+------+----------+----------+
    |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
    +----+-----+-------+------+----------+----------+
    | 1  |  1  | X'00' |  1   | Variable |    2     |
    +----+-----+-------+------+----------+----------+
  */
  header := make([]byte, 3)

  _, err := io.ReadFull(c, header)

  if err != nil {
    logs.Warn("illegal request", err)
    c.Close()
    return
  }

  switch header[1] {
  case connectMethod:
    s.handleConnect(c,ss,id)
  case bindMethod:
    s.handleBind(c)
  case associateMethod:
    s.handleUDP(c,id)
  default:
    s.sendReply(c, commandNotSupported)
    c.Close()
  }
}

//reply
func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
  reply := []byte{
    5,
    rep,
    0,
    1,
  }

  localAddr := c.LocalAddr().String()
  localHost, localPort, _ := net.SplitHostPort(localAddr)
  ipBytes := net.ParseIP(localHost).To4()
  nPort, _ := strconv.Atoi(localPort)
  reply = append(reply, ipBytes...)
  portBytes := make([]byte, 2)
  binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  reply = append(reply, portBytes...)

  c.Write(reply)
}





//do conn
func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8,ss *Sock5ModeServer,id int) {
  addrType := make([]byte, 1)
  c.Read(addrType)
  var host string
  switch addrType[0] {
  case ipV4:
    ipv4 := make(net.IP, net.IPv4len)
    c.Read(ipv4)
    host = ipv4.String()
  case ipV6:
    ipv6 := make(net.IP, net.IPv6len)
    c.Read(ipv6)
    host = ipv6.String()
  case domainName:
    var domainLen uint8
    binary.Read(c, binary.BigEndian, &domainLen)
    domain := make([]byte, domainLen)
    c.Read(domain)
    host = string(domain)
  default:
    s.sendReply(c, addrTypeNotSupported)
    return
  }

  var port uint16
  binary.Read(c, binary.BigEndian, &port)
  // connect to host
  addr := net.JoinHostPort(host, strconv.Itoa(int(port)))
  var ltype string
  if command == associateMethod {
    ltype = common.CONN_UDP
  } else {
    ltype = common.CONN_TCP
  }


  v_info,ok:=common.Vm.Get(id)
  if !ok {
    s.sendReply(c, addrTypeNotSupported)
    logs.Warn("id have not vkey",id)
    return
  }

  v_info_list:=strings.Split(v_info," ")
  v_key:=v_info_list[0]
  v_addr:=v_info_list[1]

  if addr != PublicIp+":8888" {
    //vkey=ss.vkeyManager.Get(id)
    //fmt.Println(ss.task.Client)
      Zlog("sk5", PublicIp+":"+strconv.Itoa(ss.task.Port), v_key, v_addr, ltype, addr)
  }

  client:=&Client{
    Id:id,
  }

  s.DealClient(conn.NewConn(c), client, addr, nil, ltype, func() {
    s.sendReply(c, succeeded)
  }, s.task.Flow, false, nil)
  return
}

//conn
func (s *Sock5ModeServer) handleConnect(c net.Conn,ss *Sock5ModeServer,id int) {
  s.doConnect(c, connectMethod,ss,id)
}

// passive mode
func (s *Sock5ModeServer) handleBind(c net.Conn) {
}
func (s *Sock5ModeServer) sendUdpReply(writeConn net.Conn, c net.Conn, rep uint8, serverIp string) {
  reply := []byte{
    5,
    rep,
    0,
    1,
  }
  localHost, localPort, _ := net.SplitHostPort(c.LocalAddr().String())
  localHost = serverIp
  ipBytes := net.ParseIP(localHost).To4()
  nPort, _ := strconv.Atoi(localPort)
  reply = append(reply, ipBytes...)
  portBytes := make([]byte, 2)
  binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  reply = append(reply, portBytes...)
  writeConn.Write(reply)

}

func (s *Sock5ModeServer) handleUDP(c net.Conn, id int) {
    logs.Info("开始处理 UDP 请求，客户端 ID:", id)
    defer c.Close()
    defer logs.Info("UDP 处理结束，客户端 ID:", id)

    addrType := make([]byte, 1)
    if _, err := io.ReadFull(c, addrType); err != nil {
        logs.Error("读取地址类型失败:", err)
        return
    }
    logs.Debug("读取到的地址类型: %d, 原始数据: %v", addrType[0], addrType)

    var host string
    switch addrType[0] {
    case ipV4:
        ipv4 := make(net.IP, net.IPv4len)
        if _, err := io.ReadFull(c, ipv4); err != nil {
            logs.Error("读取 IPv4 地址失败:", err)
            return
        }
        host = ipv4.String()
    case ipV6:
        ipv6 := make(net.IP, net.IPv6len)
        if _, err := io.ReadFull(c, ipv6); err != nil {
            logs.Error("读取 IPv6 地址失败:", err)
            return
        }
        host = ipv6.String()
    case domainName:
        var domainLen uint8
        if err := binary.Read(c, binary.BigEndian, &domainLen); err != nil {
            logs.Error("读取域名长度失败:", err)
            return
        }
        domain := make([]byte, domainLen)
        if _, err := io.ReadFull(c, domain); err != nil {
            logs.Error("读取域名失败:", err)
            return
        }
        host = string(domain)
    default:
        logs.Error("不支持的地址类型:", addrType[0])
        s.sendReply(c, addrTypeNotSupported)
        return
    }

    var port uint16
    if err := binary.Read(c, binary.BigEndian, &port); err != nil {
        logs.Error("读取端口失败:", err)
        return
    }
    logs.Debug("解析的目标地址: %s, 端口: %d, 原始数据: %v", host, port, []byte(host))

    v_info, ok := common.Vm.Get(id)
    if !ok {
        logs.Warn("未找到对应的客户端信息，ID:", id)
        s.sendReply(c, addrTypeNotSupported)
        return
    }
    v_info_list := strings.Split(v_info, " ")
    v_key := v_info_list[0]
    v_addr := v_info_list[1]
    logs.Debug("客户端信息 - vKey: %s, 地址: %s", v_key, v_addr)

    if host+":"+strconv.Itoa(int(port)) != PublicIp+":8888" {
        Zlog("sk5", PublicIp+":"+strconv.Itoa(s.task.Port), v_key, v_addr, "udp", host+":"+strconv.Itoa(int(port)))
    }

    replyAddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:0")
    if err != nil {
        logs.Error("解析本地回复地址失败:", err)
        return
    }
    reply, err := net.ListenUDP("udp", replyAddr)
    if err != nil {
        logs.Error("监听本地 UDP 端口失败:", err)
        s.sendReply(c, addrTypeNotSupported)
        return
    }
    defer reply.Close()
    logs.Debug("创建的本地 UDP 监听器: %v", reply.LocalAddr())

    logs.Debug("准备发送 UDP 回复")
    s.sendUdpReply(c, reply, succeeded, common.GetServerIpByClientIp(c.RemoteAddr().(*net.TCPAddr).IP))
    logs.Debug("UDP 回复已发送")

    link := conn.NewLink("udp5", "", false, false, c.RemoteAddr().String(), false)
    logs.Debug("创建的新 Link: %+v", link)

    target, err := s.bridge.SendLinkInfo(id, link, s.task)
    if err != nil {
        logs.Error("从客户端获取连接失败, ID: %d, 错误: %v", id, err)
        return
    }
    logs.Info("成功获取客户端连接")

    var clientAddr net.Addr
    go func() {
        b := common.BufPoolUdp.Get().([]byte)
        defer common.BufPoolUdp.Put(b)
        defer c.Close()
        for {
            n, laddr, err := reply.ReadFrom(b)
            if err != nil {
                logs.Error("从本地 UDP 读取数据失败:", err)
                return
            }
            logs.Debug("从本地 UDP 读取数据, 长度: %d, 地址: %s, 数据: %v", n, laddr, b[:n])
            if clientAddr == nil {
                clientAddr = laddr
                logs.Info("设置客户端地址:", clientAddr)
            }
            logs.Debug("准备向客户端写入数据, 长度: %d, 数据: %v", n, b[:n])
            if _, err := target.Write(b[:n]); err != nil {
                logs.Error("向客户端写入数据失败:", err)
                return
            }
            logs.Debug("成功向客户端写入数据, 长度: %d", n)
        }
    }()

    go func() {
        var l int32
        b := common.BufPoolUdp.Get().([]byte)
        defer common.BufPoolUdp.Put(b)
        defer c.Close()
        for {
            if err := binary.Read(target, binary.LittleEndian, &l); err != nil {
                logs.Error("读取数据长度失败:", err)
                return
            }
            logs.Debug("从客户端读取的数据长度: %d", l)
            if l >= common.PoolSizeUdp || l <= 0 {
                logs.Warn("无效的数据长度: %d", l)
                return
            }
            if _, err := io.ReadFull(target, b[:l]); err != nil {
                logs.Error("从客户端读取数据失败:", err)
                return
            }
            logs.Debug("从客户端读取数据, 长度: %d, 数据: %v", l, b[:l])
            logs.Debug("准备向用户写入数据, 长度: %d, 数据: %v", l, b[:l])
            if _, err := reply.WriteTo(b[:l], clientAddr); err != nil {
                logs.Error("向用户写入数据失败:", err)
                return
            }
            logs.Debug("成功向用户写入数据, 长度: %d", l)
        }
    }()

    b := common.BufPoolUdp.Get().([]byte)
    defer common.BufPoolUdp.Put(b)
    defer target.Close()
    for {
        n, err := c.Read(b)
        if err != nil {
            logs.Error("从连接读取数据失败: %v", err)
            return
        }
        logs.Debug("从连接读取数据, 长度: %d, 数据: %v", n, b[:n])
    }
}

//new conn
func (s *Sock5ModeServer) handleConn(c net.Conn, ss *Sock5ModeServer) {
    buf := make([]byte, 2)
    if _, err := io.ReadFull(c, buf); err != nil {
        logs.Warn("negotiation err", err)
        c.Close()
        return
    }

    if version := buf[0]; version != 5 {
        logs.Warn("only support socks5, request from: ", c.RemoteAddr())
        c.Close()
        return
    }
    nMethods := buf[1]

    methods := make([]byte, nMethods)
    if len, err := c.Read(methods); len != int(nMethods) || err != nil {
        logs.Warn("wrong method")
        c.Close()
        return
    }

    // 直接使用用户名密码认证
    buf[1] = UserPassAuth
    c.Write(buf)

    err, user, pass := s.Auth(c)
    if err != nil {
        c.Close()
        logs.Warn("Validation failed:", err)
        return
    }

    if pass == common.GetProxyPass() && user != "" {
        if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
            c.Close()
            return
        }

        id, err := strconv.Atoi(user)
        if err != nil {
            c.Close()
            return
        }
    s.handleRequest(c, ss,id)
        //ss.task.Client.Id = id

    } else {
        c.Write([]byte{userAuthVersion, authFailure})
        c.Close()
        return
    }

    
}


//socks5 auth
func (s *Sock5ModeServer) Auth(c net.Conn) (error,string,string) {

  header := []byte{0, 0}
  if _, err := io.ReadAtLeast(c, header, 2); err != nil {
    return err,"","";
  }

  if header[0] != userAuthVersion {
    return errors.New("验证方式不被支持"),"","";
  }

  userLen := int(header[1])
  user := make([]byte, userLen)
  if _, err := io.ReadAtLeast(c, user, userLen); err != nil {
    return err,"","";
  }
  if _, err := c.Read(header[:1]); err != nil {
    return errors.New("密码长度获取错误"),"","";
  }
  passLen := int(header[0])
  pass := make([]byte, passLen)
  if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
    return err,"","";
  }

  /*
  var U, P string
  if s.task.MultiAccount != nil {
    // enable multi user auth
    U = string(user)
    if len(U) == 0 {
            return errors.New("验证不通过"),"","";
    }
    var ok bool
    P, ok = s.task.MultiAccount.AccountMap[U]
    if !ok {
      return errors.New("验证不通过")
    }
  } else {
    U = s.task.Client.Cnf.U
    P = s.task.Client.Cnf.P
  }
  */

  return nil,string(user),string(pass)

  /*

  if string(user) == U && string(pass) == P {
    if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
      return err
    }
    return nil
  } else {
    if _, err := c.Write([]byte{userAuthVersion, authFailure}); err != nil {
      return err
    }
    return errors.New("验证不通过")
  }
  */
}

//start
func (s *Sock5ModeServer) Start() error {
  return conn.NewTcpListenerAndProcess("0.0.0.0"+":"+strconv.Itoa(s.task.Port), func(c net.Conn) {

/*
    if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
      logs.Warn("client id %d, task id %d, error %s, when socks5 connection", s.task.Client.Id, s.task.Id, err.Error())
      c.Close()
      return
    }
*/

    //logs.Trace("New socks5 connection,client %d,remote address %s", s.task.Client.Id, c.RemoteAddr())
    s.handleConn(c,s)

    //s.task.Client.AddConn()

  }, &s.listener)
}

//new
func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeServer {
  s := new(Sock5ModeServer)
  s.bridge = bridge
  s.task = task
  return s
}

//close
func (s *Sock5ModeServer) Close() error {
  return s.listener.Close()
}




------------------------------------------------原版本的server/proxy/socks5.go-----------------------------------------------

package proxy

import (
  "encoding/binary"
  "errors"
  "io"
  "net"
  "strconv"

  "ehang.io/nps/lib/common"
  "ehang.io/nps/lib/conn"
  "ehang.io/nps/lib/file"
  "github.com/astaxie/beego/logs"
)

const (
  ipV4            = 1
  domainName      = 3
  ipV6            = 4
  connectMethod   = 1
  bindMethod      = 2
  associateMethod = 3
  // The maximum packet size of any udp Associate packet, based on ethernet's max size,
  // minus the IP and UDP headers. IPv4 has a 20 byte header, UDP adds an
  // additional 4 bytes.  This is a total overhead of 24 bytes.  Ethernet's
  // max packet size is 1500 bytes,  1500 - 24 = 1476.
  maxUDPPacketSize = 1476
)

const (
  succeeded uint8 = iota
  serverFailure
  notAllowed
  networkUnreachable
  hostUnreachable
  connectionRefused
  ttlExpired
  commandNotSupported
  addrTypeNotSupported
)

const (
  UserPassAuth    = uint8(2)
  userAuthVersion = uint8(1)
  authSuccess     = uint8(0)
  authFailure     = uint8(1)
)

type Sock5ModeServer struct {
  BaseServer
  listener net.Listener
}

//req
func (s *Sock5ModeServer) handleRequest(c net.Conn,ss *Sock5ModeServer) {
  /*
    The SOCKS request is formed as follows:
    +----+-----+-------+------+----------+----------+
    |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
    +----+-----+-------+------+----------+----------+
    | 1  |  1  | X'00' |  1   | Variable |    2     |
    +----+-----+-------+------+----------+----------+
  */
  header := make([]byte, 3)

  _, err := io.ReadFull(c, header)

  if err != nil {
    logs.Warn("illegal request", err)
    c.Close()
    return
  }

  switch header[1] {
  case connectMethod:
    s.handleConnect(c,ss)
  case bindMethod:
    s.handleBind(c)
  case associateMethod:
    s.handleUDP(c)
  default:
    s.sendReply(c, commandNotSupported)
    c.Close()
  }
}

//reply
func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
  reply := []byte{
    5,
    rep,
    0,
    1,
  }

  localAddr := c.LocalAddr().String()
  localHost, localPort, _ := net.SplitHostPort(localAddr)
  ipBytes := net.ParseIP(localHost).To4()
  nPort, _ := strconv.Atoi(localPort)
  reply = append(reply, ipBytes...)
  portBytes := make([]byte, 2)
  binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  reply = append(reply, portBytes...)

  c.Write(reply)
}

//do conn
func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8,ss *Sock5ModeServer) {
  addrType := make([]byte, 1)
  c.Read(addrType)
  var host string
  switch addrType[0] {
  case ipV4:
    ipv4 := make(net.IP, net.IPv4len)
    c.Read(ipv4)
    host = ipv4.String()
  case ipV6:
    ipv6 := make(net.IP, net.IPv6len)
    c.Read(ipv6)
    host = ipv6.String()
  case domainName:
    var domainLen uint8
    binary.Read(c, binary.BigEndian, &domainLen)
    domain := make([]byte, domainLen)
    c.Read(domain)
    host = string(domain)
  default:
    s.sendReply(c, addrTypeNotSupported)
    return
  }

  var port uint16
  binary.Read(c, binary.BigEndian, &port)
  // connect to host
  addr := net.JoinHostPort(host, strconv.Itoa(int(port)))
  var ltype string
  if command == associateMethod {
    ltype = common.CONN_UDP
  } else {
    ltype = common.CONN_TCP
  }



  if addr != PublicIp+":8888" {
      Zlog("sk5", PublicIp+":"+strconv.Itoa(ss.task.Port), ss.task.Client.VerifyKey, ss.task.Client.Addr, ltype, addr)
  }


  s.DealClient(conn.NewConn(c), s.task.Client, addr, nil, ltype, func() {
    s.sendReply(c, succeeded)
  }, s.task.Flow, s.task.Target.LocalProxy, nil)
  return
}

//conn
func (s *Sock5ModeServer) handleConnect(c net.Conn,ss *Sock5ModeServer) {
  s.doConnect(c, connectMethod,ss)
}

// passive mode
func (s *Sock5ModeServer) handleBind(c net.Conn) {
}
func (s *Sock5ModeServer) sendUdpReply(writeConn net.Conn, c net.Conn, rep uint8, serverIp string) {
  reply := []byte{
    5,
    rep,
    0,
    1,
  }
  localHost, localPort, _ := net.SplitHostPort(c.LocalAddr().String())
  localHost = serverIp
  ipBytes := net.ParseIP(localHost).To4()
  nPort, _ := strconv.Atoi(localPort)
  reply = append(reply, ipBytes...)
  portBytes := make([]byte, 2)
  binary.BigEndian.PutUint16(portBytes, uint16(nPort))
  reply = append(reply, portBytes...)
  writeConn.Write(reply)

}

func (s *Sock5ModeServer) handleUDP(c net.Conn) {
  defer c.Close()
  addrType := make([]byte, 1)
  c.Read(addrType)
  var host string
  switch addrType[0] {
  case ipV4:
    ipv4 := make(net.IP, net.IPv4len)
    c.Read(ipv4)
    host = ipv4.String()
  case ipV6:
    ipv6 := make(net.IP, net.IPv6len)
    c.Read(ipv6)
    host = ipv6.String()
  case domainName:
    var domainLen uint8
    binary.Read(c, binary.BigEndian, &domainLen)
    domain := make([]byte, domainLen)
    c.Read(domain)
    host = string(domain)
  default:
    s.sendReply(c, addrTypeNotSupported)
    return
  }
  //读取端口
  var port uint16
  binary.Read(c, binary.BigEndian, &port)
  logs.Warn(host, string(port))
  replyAddr, err := net.ResolveUDPAddr("udp", s.task.ServerIp+":0")
  if err != nil {
    logs.Error("build local reply addr error", err)
    return
  }
  reply, err := net.ListenUDP("udp", replyAddr)
  if err != nil {
    s.sendReply(c, addrTypeNotSupported)
    logs.Error("listen local reply udp port error")
    return
  }
  // reply the local addr
  s.sendUdpReply(c, reply, succeeded, common.GetServerIpByClientIp(c.RemoteAddr().(*net.TCPAddr).IP))
  defer reply.Close()
  // new a tunnel to client
  link := conn.NewLink("udp5", "", s.task.Client.Cnf.Crypt, s.task.Client.Cnf.Compress, c.RemoteAddr().String(), false)
  target, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, s.task)
  if err != nil {
    logs.Warn("get connection from client id %d  error %s", s.task.Client.Id, err.Error())
    return
  }

  var clientAddr net.Addr
  // copy buffer
  go func() {
    b := common.BufPoolUdp.Get().([]byte)
    defer common.BufPoolUdp.Put(b)
    defer c.Close()

    for {
      n, laddr, err := reply.ReadFrom(b)
      if err != nil {
        logs.Error("read data from %s err %s", reply.LocalAddr().String(), err.Error())
        return
      }
      if clientAddr == nil {
        clientAddr = laddr
      }
      if _, err := target.Write(b[:n]); err != nil {
        logs.Error("write data to client error", err.Error())
        return
      }
    }
  }()

  go func() {
    var l int32
    b := common.BufPoolUdp.Get().([]byte)
    defer common.BufPoolUdp.Put(b)
    defer c.Close()
    for {
      if err := binary.Read(target, binary.LittleEndian, &l); err != nil || l >= common.PoolSizeUdp || l <= 0 {
        logs.Warn("read len bytes error", err.Error())
        return
      }
      binary.Read(target, binary.LittleEndian, b[:l])
      if err != nil {
        logs.Warn("read data form client error", err.Error())
        return
      }
      if _, err := reply.WriteTo(b[:l], clientAddr); err != nil {
        logs.Warn("write data to user ", err.Error())
        return
      }
    }
  }()

  b := common.BufPoolUdp.Get().([]byte)
  defer common.BufPoolUdp.Put(b)
  defer target.Close()
  for {
    _, err := c.Read(b)
    if err != nil {
      c.Close()
      return
    }
  }
}

//new conn
func (s *Sock5ModeServer) handleConn(c net.Conn,ss *Sock5ModeServer) {
  buf := make([]byte, 2)
  if _, err := io.ReadFull(c, buf); err != nil {
    logs.Warn("negotiation err", err)
    c.Close()
    return
  }

  if version := buf[0]; version != 5 {
    logs.Warn("only support socks5, request from: ", c.RemoteAddr())
    c.Close()
    return
  }
  nMethods := buf[1]

  methods := make([]byte, nMethods)
  if len, err := c.Read(methods); len != int(nMethods) || err != nil {
    logs.Warn("wrong method")
    c.Close()
    return
  }
  if (s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "") || (s.task.MultiAccount != nil && len(s.task.MultiAccount.AccountMap) > 0) {
    buf[1] = UserPassAuth
    c.Write(buf)
    if err := s.Auth(c); err != nil {
      c.Close()
      logs.Warn("Validation failed:", err)
      return
    }
  } else {
    buf[1] = 0
    c.Write(buf)
  }
  s.handleRequest(c,ss)
}

//socks5 auth
func (s *Sock5ModeServer) Auth(c net.Conn) error {
  header := []byte{0, 0}
  if _, err := io.ReadAtLeast(c, header, 2); err != nil {
    return err
  }
  if header[0] != userAuthVersion {
    return errors.New("验证方式不被支持")
  }
  userLen := int(header[1])
  user := make([]byte, userLen)
  if _, err := io.ReadAtLeast(c, user, userLen); err != nil {
    return err
  }
  if _, err := c.Read(header[:1]); err != nil {
    return errors.New("密码长度获取错误")
  }
  passLen := int(header[0])
  pass := make([]byte, passLen)
  if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
    return err
  }

  var U, P string
  if s.task.MultiAccount != nil {
    // enable multi user auth
    U = string(user)
    if len(U) == 0 {
            return errors.New("验证不通过")
    }
    var ok bool
    P, ok = s.task.MultiAccount.AccountMap[U]
    if !ok {
      return errors.New("验证不通过")
    }
  } else {
    U = s.task.Client.Cnf.U
    P = s.task.Client.Cnf.P
  }

  if string(user) == U && string(pass) == P {
    if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
      return err
    }
    return nil
  } else {
    if _, err := c.Write([]byte{userAuthVersion, authFailure}); err != nil {
      return err
    }
    return errors.New("验证不通过")
  }
}

//start
func (s *Sock5ModeServer) Start() error {
  return conn.NewTcpListenerAndProcess(s.task.ServerIp+":"+strconv.Itoa(s.task.Port), func(c net.Conn) {
    if err := s.CheckFlowAndConnNum(s.task.Client); err != nil {
      logs.Warn("client id %d, task id %d, error %s, when socks5 connection", s.task.Client.Id, s.task.Id, err.Error())
      c.Close()
      return
    }
    logs.Trace("New socks5 connection,client %d,remote address %s", s.task.Client.Id, c.RemoteAddr())
    s.handleConn(c,s)
    s.task.Client.AddConn()
  }, &s.listener)
}

//new
func NewSock5ModeServer(bridge NetBridge, task *file.Tunnel) *Sock5ModeServer {
  s := new(Sock5ModeServer)
  s.bridge = bridge
  s.task = task
  return s
}

//close
func (s *Sock5ModeServer) Close() error {
  return s.listener.Close()
}





--------------------------------我改后的client.go-----------------------------------------------

package client

import (
  "bufio"
  "bytes"
  "hzserver/lib/nps_mux"
  "net"
  "net/http"
  "strconv"
  "strings"
  "sync"
  "time"

  "github.com/astaxie/beego/logs"
  "github.com/xtaci/kcp-go"

  "hzserver/lib/common"
  "hzserver/lib/config"
  "hzserver/lib/conn"
  "hzserver/lib/crypt"
)

type TRPClient struct {
  svrAddr        string
  bridgeConnType string
  proxyUrl       string
  vKey           string
  p2pAddr        map[string]string
  tunnel         *nps_mux.Mux
  signal         *conn.Conn
  ticker         *time.Ticker
  cnf            *config.Config
  disconnectTime int
  once           sync.Once
}

//new client
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
  return &TRPClient{
    svrAddr:        svraddr,
    p2pAddr:        make(map[string]string, 0),
    vKey:           vKey,
    bridgeConnType: bridgeConnType,
    proxyUrl:       proxyUrl,
    cnf:            cnf,
    disconnectTime: disconnectTime,
    once:           sync.Once{},
  }
}

var NowStatus int
var CloseClient bool

//start
func (s *TRPClient) Start() {
  CloseClient = false
retry:
  if CloseClient {
    return
  }
  NowStatus = 0
  c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
  if err != nil {
    logs.Error("The connection server failed and will be reconnected in five seconds, error", err.Error())
    time.Sleep(time.Second * 5)
    goto retry
  }
  if c == nil {
    logs.Error("Error data from server, and will be reconnected in five seconds")
    time.Sleep(time.Second * 5)
    goto retry
  }
  logs.Info("Successful connection with server %s", s.svrAddr)
  //monitor the connection
  go s.ping()
  s.signal = c
  //start a channel connection
  go s.newChan()
  //start health check if the it's open
  if s.cnf != nil && len(s.cnf.Healths) > 0 {
    go heathCheck(s.cnf.Healths, s.signal)
  }
  NowStatus = 1
  //msg connection, eg udp
  s.handleMain()
}

//handle main connection
func (s *TRPClient) handleMain() {
  for {
    flags, err := s.signal.ReadFlag()
    if err != nil {
      logs.Error("Accept server data error %s, end this service", err.Error())
      break
    }
    switch flags {
    case common.NEW_UDP_CONN:
      logs.Info("NEW_UDP_CONN 11111111111111")
      //read server udp addr and password
      if lAddr, err := s.signal.GetShortLenContent(); err != nil {
        logs.Warn(err)
        return
      } else if pwd, err := s.signal.GetShortLenContent(); err == nil {
        var localAddr string
        //The local port remains unchanged for a certain period of time
        if v, ok := s.p2pAddr[crypt.Md5(string(pwd)+strconv.Itoa(int(time.Now().Unix()/100)))]; !ok {
          tmpConn, err := common.GetLocalUdpAddr()
          if err != nil {
            logs.Error(err)
            return
          }
          localAddr = tmpConn.LocalAddr().String()
        } else {
          localAddr = v
        }
        go s.newUdpConn(localAddr, string(lAddr), string(pwd))
      }
    }
  }
  s.Close()
}

func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
  var localConn net.PacketConn
  var err error
  var remoteAddress string
  if remoteAddress, localConn, err = handleP2PUdp(localAddr, rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
    logs.Error(err)
    return
  }
  l, err := kcp.ServeConn(nil, 150, 3, localConn)
  if err != nil {
    logs.Error(err)
    return
  }
  logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
  for {
    udpTunnel, err := l.AcceptKCP()
    if err != nil {
      logs.Error(err)
      l.Close()
      return
    }
    if udpTunnel.RemoteAddr().String() == string(remoteAddress) {
      conn.SetUdpSession(udpTunnel)
      logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
      //read link info from remote
      conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
        go s.handleChan(c)
      })
      break
    }
  }
}

//pmux tunnel
func (s *TRPClient) newChan() {
  tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
  if err != nil {
    logs.Error("connect to ", s.svrAddr, "error:", err)
    return
  }
  s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
  for {
    src, err := s.tunnel.Accept()
    if err != nil {
      logs.Warn(err)
      s.Close()
      break
    }
    go s.handleChan(src)
  }
}

func (s *TRPClient) handleChan(src net.Conn) {
  lk, err := conn.NewConn(src).GetLinkInfo()
  if err != nil || lk == nil {
    src.Close()
    logs.Error("get connection info from server error ", err)
    return
  }
  //host for target processing
  lk.Host = common.FormatAddress(lk.Host)
  //if Conn type is http, read the request and log
  if lk.ConnType == "http" {
    if targetConn, err := net.DialTimeout(common.CONN_TCP, lk.Host, lk.Option.Timeout); err != nil {
      logs.Warn("connect to %s error %s", lk.Host, err.Error())
      src.Close()
    } else {
      srcConn := conn.GetConn(src, lk.Crypt, lk.Compress, nil, false)
      go func() {
        common.CopyBuffer(srcConn, targetConn)
        srcConn.Close()
        targetConn.Close()
      }()
      for {
        if r, err := http.ReadRequest(bufio.NewReader(srcConn)); err != nil {
          srcConn.Close()
          targetConn.Close()
          break
        } else {
          remoteAddr := strings.TrimSpace(r.Header.Get("X-Forwarded-For"))
          if len(remoteAddr) == 0 {
            remoteAddr = r.RemoteAddr
          }
          logs.Trace("http request, method %s, host %s, url %s, remote address %s", r.Method, r.Host, r.URL.Path, remoteAddr)
          r.Write(targetConn)
        }
      }
    }
    return
  }

  if lk.ConnType == "udp5" {

    
    logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
    s.handleUdp(src)

    //lk.ConnType="udp4"
  }
  //connect to target if conn type is tcp or udp

  if targetConn, err := net.DialTimeout(lk.ConnType, lk.Host, lk.Option.Timeout); err != nil {
    logs.Warn("connect to %s error %s", lk.Host, err.Error())

    src.Close()
  } else {
    logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
    conn.CopyWaitGroup(src, targetConn, lk.Crypt, lk.Compress, nil, nil, false, nil)
  }
}

func (s *TRPClient) handleUdp(serverConn net.Conn) {
    logs.Info("开始处理来自服务器的 UDP 数据")
    // bind a local udp port
    local, err := net.ListenUDP("udp", nil)
    defer serverConn.Close()
    if err != nil {
        logs.Error("绑定本地 UDP 端口失败: ", err.Error())
        return
    }
    defer local.Close()

    logs.Debug("绑定的本地 UDP 地址: %v", local.LocalAddr())

    go func() {
        defer serverConn.Close()
        b := common.BufPoolUdp.Get().([]byte)
        defer common.BufPoolUdp.Put(b)
        for {
            n, raddr, err := local.ReadFrom(b)
            if err != nil {
                logs.Error("从本地 UDP 读取数据失败: ", err.Error())
                return
            }
            logs.Debug("从本地 UDP 读取数据, 长度: %d, 远程地址: %s, 原始数据: %v", n, raddr.String(), b[:n])

            buf := bytes.Buffer{}
            dgram := common.NewUDPDatagram(common.NewUDPHeader(0, 0, common.ToSocksAddr(raddr)), b[:n])
            dgram.Write(&buf)
            b, err := conn.GetLenBytes(buf.Bytes())
            if err != nil {
                logs.Warn("获取长度字节失败: ", err.Error())
                continue
            }
            logs.Debug("准备向服务器写入的 UDP 数据: %v", buf.Bytes())
            logs.Debug("准备向服务器写入数据, 长度: %d", len(b))
            if _, err := serverConn.Write(b); err != nil {
                logs.Error("向服务器写入数据失败: ", err.Error())
                return
            }
            logs.Debug("成功向服务器写入数据")
        }
    }()

    b := common.BufPoolUdp.Get().([]byte)
    defer common.BufPoolUdp.Put(b)
    for {
        n, err := serverConn.Read(b)
        if err != nil {
            logs.Error("从服务器读取 UDP 数据失败: ", err.Error())
            return
        }
        logs.Debug("从服务器读取 UDP 数据, 长度: %d, 原始数据: %v", n, b[:n])

        udpData, err := common.ReadUDPDatagram(bytes.NewReader(b[:n]))
        if err != nil {
            logs.Error("解析 UDP 数据包失败: ", err.Error())
            return
        }
        logs.Debug("解析后的 UDP 数据包: %+v", udpData)
        logs.Debug("成功解析 UDP 数据包, 目标地址: %s", udpData.Header.Addr.String())

        raddr, err := net.ResolveUDPAddr("udp", udpData.Header.Addr.String())
        if err != nil {
            logs.Error("解析远程地址失败: ", err.Error())
            continue // drop silently
        }
        logs.Debug("解析远程地址成功: %s", raddr.String())

        logs.Debug("准备向本地 UDP 写入数据: %v", udpData.Data)
        _, err = local.WriteTo(udpData.Data, raddr)
        if err != nil {
            logs.Error("向本地 UDP 写入数据失败, 目标地址: %s, 错误: %s", raddr.String(), err.Error())
            return
        }
        logs.Debug("成功向本地 UDP 写入数据, 目标地址: %s, 数据长度: %d", raddr.String(), len(udpData.Data))
    }
}



// Whether the monitor channel is closed
func (s *TRPClient) ping() {
  s.ticker = time.NewTicker(time.Second * 5)
loop:
  for {
    select {
    case <-s.ticker.C:
      if s.tunnel != nil && s.tunnel.IsClose {
        s.Close()
        break loop
      }
    }
  }
}

func (s *TRPClient) Close() {
  s.once.Do(s.closing)
}

func (s *TRPClient) closing() {
  CloseClient = true
  NowStatus = 0
  if s.tunnel != nil {
    _ = s.tunnel.Close()
  }
  if s.signal != nil {
    _ = s.signal.Close()
  }
  if s.ticker != nil {
    s.ticker.Stop()
  }
}


---------------------------------------原版本的client.go----------------------------------------------


package client

import (
  "bufio"
  "bytes"
  "ehang.io/nps/lib/nps_mux"
  "net"
  "net/http"
  "strconv"
  "strings"
  "sync"
  "time"

  "github.com/astaxie/beego/logs"
  "github.com/xtaci/kcp-go"

  "ehang.io/nps/lib/common"
  "ehang.io/nps/lib/config"
  "ehang.io/nps/lib/conn"
  "ehang.io/nps/lib/crypt"
)

type TRPClient struct {
  svrAddr        string
  bridgeConnType string
  proxyUrl       string
  vKey           string
  p2pAddr        map[string]string
  tunnel         *nps_mux.Mux
  signal         *conn.Conn
  ticker         *time.Ticker
  cnf            *config.Config
  disconnectTime int
  once           sync.Once
}

//new client
func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl string, cnf *config.Config, disconnectTime int) *TRPClient {
  return &TRPClient{
    svrAddr:        svraddr,
    p2pAddr:        make(map[string]string, 0),
    vKey:           vKey,
    bridgeConnType: bridgeConnType,
    proxyUrl:       proxyUrl,
    cnf:            cnf,
    disconnectTime: disconnectTime,
    once:           sync.Once{},
  }
}

var NowStatus int
var CloseClient bool

//start
func (s *TRPClient) Start() {
  CloseClient = false
retry:
  if CloseClient {
    return
  }
  NowStatus = 0
  c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
  if err != nil {
    logs.Error("The connection server failed and will be reconnected in five seconds, error", err.Error())
    time.Sleep(time.Second * 5)
    goto retry
  }
  if c == nil {
    logs.Error("Error data from server, and will be reconnected in five seconds")
    time.Sleep(time.Second * 5)
    goto retry
  }
  logs.Info("Successful connection with server %s", s.svrAddr)
  //monitor the connection
  go s.ping()
  s.signal = c
  //start a channel connection
  go s.newChan()
  //start health check if the it's open
  if s.cnf != nil && len(s.cnf.Healths) > 0 {
    go heathCheck(s.cnf.Healths, s.signal)
  }
  NowStatus = 1
  //msg connection, eg udp
  s.handleMain()
}

//handle main connection
func (s *TRPClient) handleMain() {
  for {
    flags, err := s.signal.ReadFlag()
    if err != nil {
      logs.Error("Accept server data error %s, end this service", err.Error())
      break
    }
    switch flags {
    case common.NEW_UDP_CONN:
      //read server udp addr and password
      if lAddr, err := s.signal.GetShortLenContent(); err != nil {
        logs.Warn(err)
        return
      } else if pwd, err := s.signal.GetShortLenContent(); err == nil {
        var localAddr string
        //The local port remains unchanged for a certain period of time
        if v, ok := s.p2pAddr[crypt.Md5(string(pwd)+strconv.Itoa(int(time.Now().Unix()/100)))]; !ok {
          tmpConn, err := common.GetLocalUdpAddr()
          if err != nil {
            logs.Error(err)
            return
          }
          localAddr = tmpConn.LocalAddr().String()
        } else {
          localAddr = v
        }
        go s.newUdpConn(localAddr, string(lAddr), string(pwd))
      }
    }
  }
  s.Close()
}

func (s *TRPClient) newUdpConn(localAddr, rAddr string, md5Password string) {
  var localConn net.PacketConn
  var err error
  var remoteAddress string
  if remoteAddress, localConn, err = handleP2PUdp(localAddr, rAddr, md5Password, common.WORK_P2P_PROVIDER); err != nil {
    logs.Error(err)
    return
  }
  l, err := kcp.ServeConn(nil, 150, 3, localConn)
  if err != nil {
    logs.Error(err)
    return
  }
  logs.Trace("start local p2p udp listen, local address", localConn.LocalAddr().String())
  for {
    udpTunnel, err := l.AcceptKCP()
    if err != nil {
      logs.Error(err)
      l.Close()
      return
    }
    if udpTunnel.RemoteAddr().String() == string(remoteAddress) {
      conn.SetUdpSession(udpTunnel)
      logs.Trace("successful connection with client ,address %s", udpTunnel.RemoteAddr().String())
      //read link info from remote
      conn.Accept(nps_mux.NewMux(udpTunnel, s.bridgeConnType, s.disconnectTime), func(c net.Conn) {
        go s.handleChan(c)
      })
      break
    }
  }
}

//pmux tunnel
func (s *TRPClient) newChan() {
  tunnel, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
  if err != nil {
    logs.Error("connect to ", s.svrAddr, "error:", err)
    return
  }
  s.tunnel = nps_mux.NewMux(tunnel.Conn, s.bridgeConnType, s.disconnectTime)
  for {
    src, err := s.tunnel.Accept()
    if err != nil {
      logs.Warn(err)
      s.Close()
      break
    }
    go s.handleChan(src)
  }
}

func (s *TRPClient) handleChan(src net.Conn) {
  lk, err := conn.NewConn(src).GetLinkInfo()
  if err != nil || lk == nil {
    src.Close()
    logs.Error("get connection info from server error ", err)
    return
  }
  //host for target processing
  lk.Host = common.FormatAddress(lk.Host)
  //if Conn type is http, read the request and log
  if lk.ConnType == "http" {
    if targetConn, err := net.DialTimeout(common.CONN_TCP, lk.Host, lk.Option.Timeout); err != nil {
      logs.Warn("connect to %s error %s", lk.Host, err.Error())
      src.Close()
    } else {
      srcConn := conn.GetConn(src, lk.Crypt, lk.Compress, nil, false)
      go func() {
        common.CopyBuffer(srcConn, targetConn)
        srcConn.Close()
        targetConn.Close()
      }()
      for {
        if r, err := http.ReadRequest(bufio.NewReader(srcConn)); err != nil {
          srcConn.Close()
          targetConn.Close()
          break
        } else {
          remoteAddr := strings.TrimSpace(r.Header.Get("X-Forwarded-For"))
          if len(remoteAddr) == 0 {
            remoteAddr = r.RemoteAddr
          }
          logs.Trace("http request, method %s, host %s, url %s, remote address %s", r.Method, r.Host, r.URL.Path, remoteAddr)
          r.Write(targetConn)
        }
      }
    }
    return
  }
  if lk.ConnType == "udp5" {
    logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
    s.handleUdp(src)
  }
  //connect to target if conn type is tcp or udp
  if targetConn, err := net.DialTimeout(lk.ConnType, lk.Host, lk.Option.Timeout); err != nil {
    logs.Warn("connect to %s error %s", lk.Host, err.Error())
    src.Close()
  } else {
    logs.Trace("new %s connection with the goal of %s, remote address:%s", lk.ConnType, lk.Host, lk.RemoteAddr)
    conn.CopyWaitGroup(src, targetConn, lk.Crypt, lk.Compress, nil, nil, false, nil, nil)
  }
}

func (s *TRPClient) handleUdp(serverConn net.Conn) {
  // bind a local udp port
  local, err := net.ListenUDP("udp", nil)
  defer serverConn.Close()
  if err != nil {
    logs.Error("bind local udp port error ", err.Error())
    return
  }
  defer local.Close()
  go func() {
    defer serverConn.Close()
    b := common.BufPoolUdp.Get().([]byte)
    defer common.BufPoolUdp.Put(b)
    for {
      n, raddr, err := local.ReadFrom(b)
      if err != nil {
        logs.Error("read data from remote server error", err.Error())
      }
      buf := bytes.Buffer{}
      dgram := common.NewUDPDatagram(common.NewUDPHeader(0, 0, common.ToSocksAddr(raddr)), b[:n])
      dgram.Write(&buf)
      b, err := conn.GetLenBytes(buf.Bytes())
      if err != nil {
        logs.Warn("get len bytes error", err.Error())
        continue
      }
      if _, err := serverConn.Write(b); err != nil {
        logs.Error("write data to remote  error", err.Error())
        return
      }
    }
  }()
  b := common.BufPoolUdp.Get().([]byte)
  defer common.BufPoolUdp.Put(b)
  for {
    n, err := serverConn.Read(b)
    if err != nil {
      logs.Error("read udp data from server error ", err.Error())
      return
    }

    udpData, err := common.ReadUDPDatagram(bytes.NewReader(b[:n]))
    if err != nil {
      logs.Error("unpack data error", err.Error())
      return
    }
    raddr, err := net.ResolveUDPAddr("udp", udpData.Header.Addr.String())
    if err != nil {
      logs.Error("build remote addr err", err.Error())
      continue // drop silently
    }
    _, err = local.WriteTo(udpData.Data, raddr)
    if err != nil {
      logs.Error("write data to remote ", raddr.String(), "error", err.Error())
      return
    }
  }
}

// Whether the monitor channel is closed
func (s *TRPClient) ping() {
  s.ticker = time.NewTicker(time.Second * 5)
loop:
  for {
    select {
    case <-s.ticker.C:
      if s.tunnel != nil && s.tunnel.IsClose {
        s.Close()
        break loop
      }
    }
  }
}

func (s *TRPClient) Close() {
  s.once.Do(s.closing)
}

func (s *TRPClient) closing() {
  CloseClient = true
  NowStatus = 0
  if s.tunnel != nil {
    _ = s.tunnel.Close()
  }
  if s.signal != nil {
    _ = s.signal.Close()
  }
  if s.ticker != nil {
    s.ticker.Stop()
  }
}














这是原版本的客户端日志
2024/09/27 05:28:46.299 [D] [client.go:209]  new udp5 connection with the goal of 127.0.0.1:, remote address:110.40.128.73:42778
2024/09/27 05:28:46.299 [I] [client.go:223]  开始处理来自服务器的 UDP 数据
2024/09/27 05:28:46.299 [I] [client.go:233]  成功绑定本地 UDP 端口:  [::]:25397
2024/09/27 05:28:46.506 [D] [client.go:272]  从服务器读取 UDP 数据, 长度:  28
2024/09/27 05:28:46.506 [D] [client.go:279]  成功解析 UDP 数据包, 目标地址:  110.42.109.176:36789
2024/09/27 05:28:46.506 [D] [client.go:286]  解析远程地址成功:  110.42.109.176:36789
2024/09/27 05:28:46.506 [D] [client.go:293]  成功向本地 UDP 写入数据, 目标地址:  110.42.109.176:36789 , 数据长度:  18
2024/09/27 05:28:46.716 [D] [client.go:245]  从本地 UDP 读取数据, 长度:  35 , 远程地址:  110.42.109.176:36789
2024/09/27 05:28:46.716 [D] [client.go:255]  准备向服务器写入数据, 长度:  49
2024/09/27 05:28:46.716 [D] [client.go:260]  成功向服务器写入数据
2024/09/27 05:28:46.927 [E] [client.go:269]  从服务器读取 UDP 数据失败:  EOF
2024/09/27 05:28:46.928 [E] [client.go:242]  从本地 UDP 读取数据失败:  read udp [::]:25397: use of closed network connection
2024/09/27 05:28:46.928 [W] [client.go:214]  connect to 127.0.0.1: error dial udp5: unknown network udp5


这是我改的的客户端日志
2024/09/27 12:29:41.070 [D] [client.go:216]  new udp5 connection with the goal of 127.0.0.1:, remote address:110.40.128.73:46772
2024/09/27 12:29:41.070 [I] [client.go:236]  开始处理来自服务器的 UDP 数据
2024/09/27 12:29:41.070 [I] [client.go:246]  成功绑定本地 UDP 端口:  [::]:33366
2024/09/27 12:29:46.074 [E] [client.go:282]  从服务器读取 UDP 数据失败:  EOF

2024/09/27 12:29:46.074 [E] [client.go:255]  从本地 UDP 读取数据失败:  read udp [::]:33366: use of closed network connection
2024/09/27 12:29:46.074 [W] [client.go:226]  connect to 127.0.0.1: error dial udp5: unknown network udp5






这是原版本服务端的日志
2024/09/27 06:06:37.727 [I] [socks5.go:198]  开始处理 UDP 请求
2024/09/27 06:06:37.727 [D] [socks5.go:207]  读取到的地址类型: 3
2024/09/27 06:06:37.727 [I] [socks5.go:248]  读取到的目标地址: 0 端口: 51987
2024/09/27 06:06:37.727 [I] [socks5.go:262]  本地 UDP 监听地址: [::]:35736
2024/09/27 06:06:37.761 [I] [socks5.go:265]  已发送 UDP 回复
2024/09/27 06:06:37.762 [D] [socks5.go:268]  创建新的 Link: &{udp5  false false false 110.40.128.73:60138 {5s}}
2024/09/27 06:06:37.764 [I] [socks5.go:275]  成功获取客户端连接
2024/09/27 06:06:37.971 [D] [socks5.go:288]  从本地 UDP 读取数据, 长度: 28 地址: 110.40.128.73:51987
2024/09/27 06:06:37.972 [I] [socks5.go:291]  设置客户端地址: 110.40.128.73:51987
2024/09/27 06:06:37.973 [D] [socks5.go:297]  成功向客户端写入数据, 长度: 28
2024/09/27 06:06:38.178 [D] [socks5.go:319]  从客户端读取数据, 长度: 45
2024/09/27 06:06:38.178 [D] [socks5.go:324]  成功向用户写入数据, 长度: 45
2024/09/27 06:06:38.390 [E] [socks5.go:334]  从连接读取数据失败: EOF
2024/09/27 06:06:38.391 [E] [socks5.go:285]  从本地 UDP 读取数据失败: read udp [::]:35736: use of closed network connection
2024/09/27 06:06:38.391 [I] [socks5.go:335]  UDP 处理结束
2024/09/27 06:06:38.391 [E] [socks5.go:308]  读取数据长度失败: EOF



这是我改的服务端版本
2024/09/27 13:09:03.349 [I]  开始处理 UDP 请求，客户端 ID: 1
2024/09/27 13:09:03.349 [D]  读取到的地址类型: 3
2024/09/27 13:09:03.349 [I]  读取到的目标地址: 0 端口: 60680
2024/09/27 13:09:03.349 [D]  客户端信息 - vKey: =test 地址: 110.40.128.73:39610
2024/09/27 13:09:03.349 [I]  本地 UDP 监听地址: [::]:51531
2024/09/27 13:09:03.956 [I]  已发送 UDP 回复
2024/09/27 13:09:03.957 [D]  创建新的 Link: &{udp5  false false false 110.40.128.73:45832 {5s}}
2024/09/27 13:09:03.959 [I]  成功获取客户端连接
2024/09/27 13:09:08.964 [E]  从连接读取数据失败: EOF
2024/09/27 13:09:08.964 [E]  从本地 UDP 读取数据失败: read udp [::]:51531: use of closed network connection
2024/09/27 13:09:08.964 [I]  UDP 处理结束，客户端 ID: 1
2024/09/27 13:09:08.964 [E]  读取数据长度失败: EOF



所有的udp的实现细节我是没改动的，只是为了实现我最开始说的两点做了些修改，
我改后的版本的socks5代理用于请求网站是正常的，只是无法用于udp的转发，帮我看下问题在哪，如果还需要提供更多信息请告诉我，
或者你也无法确定问题的原因，请告诉我如何进一步定位，用中文回复