diff --git a/README.md b/README.md index 7da5965..8c3f1e0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ 检查 ip 时需要判断同一 ip 的不同写法 -客户端重连后出现连接卡死的情况 +客户端断联后,服务端代理端口没有正确关闭 + +代理节点超时控制 实现一个 socks context 以在子组件中获取 socks 相关信息 diff --git a/client/service.go b/client/service.go new file mode 100644 index 0000000..27b9ff2 --- /dev/null +++ b/client/service.go @@ -0,0 +1,211 @@ +package client + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "log/slog" + "net" + "os" + "proxy-server/pkg/utils" + "strconv" + "time" + + "github.com/joho/godotenv" + "github.com/pkg/errors" +) + +type Config struct { + FrpHost string + FrpCtrlPort uint16 + FrpDataPort uint16 + FwdPort uint16 + RetryInterval int +} + +var cfg Config + +var frpCtrlAddr string +var frpDataAddr string + +func Start() { + + initLog() + initEnv() + + frpCtrlAddr = net.JoinHostPort(cfg.FrpHost, strconv.Itoa(int(cfg.FrpCtrlPort))) + frpDataAddr = net.JoinHostPort(cfg.FrpHost, strconv.Itoa(int(cfg.FrpDataPort))) + + // 建立控制通道 + for { + slog.Info("建立控制通道", "addr", frpCtrlAddr) + err := control() + if err != nil { + slog.Error("建立控制通道失败", err) + slog.Info(fmt.Sprintf("%d 秒后重试", cfg.RetryInterval)) + time.Sleep(time.Duration(cfg.RetryInterval) * time.Second) + } + } +} + +func control() error { + conn, err := net.Dial("tcp", frpCtrlAddr) + if err != nil { + return errors.Wrap(err, "连接失败") + } + defer utils.Close(conn) + + // 请求转发端口 + slog.Info("注册转发端口", "port", cfg.FwdPort) + portBuf := make([]byte, 2) + binary.BigEndian.PutUint16(portBuf, cfg.FwdPort) + _, err = conn.Write(portBuf) + if err != nil { + return errors.Wrap(err, "注册转发端口失败") + } + + // 等待用户连接 + // 读写失败后退出重连,防止后续数据读写顺序错位导致卡死控制通道 + for { + slog.Info("等待用户连接") + reader := bufio.NewReader(conn) + + tagLen, err := utils.ReadByte(reader) + if err != nil { + return errors.Wrap(err, "接收 tagLen 失败") + } + tagBuf, err := utils.ReadBuffer(reader, int(tagLen)) + if err != nil { + return errors.Wrap(err, "接收 tagBuf 失败") + } + + // 建立数据通道 + go func() { + slog.Info("收到用户连接,建立数据通道") + err := data(tagLen, tagBuf) + if err != nil { + slog.Error("建立数据通道失败", err) + } + }() + } +} + +func data(tagLen byte, tagBuf []byte) error { + timerAll := time.Now() + src, err := net.Dial("tcp", frpDataAddr) + if err != nil { + return errors.Wrap(err, "连接失败") + } + defer utils.Close(src) + + // 发送 tag + slog.Info("准备代理流量") + writeBuf := make([]byte, 1+len(tagBuf)) + writeBuf[0] = tagLen + copy(writeBuf[1:], tagBuf) + _, err = src.Write(writeBuf) + if err != nil { + return errors.Wrap(err, "发送 tag 失败") + } + + // 接收目标地址 + slog.Info("接收目标地址") + addrLen, err := utils.ReadByte(src) + if err != nil { + return errors.Wrap(err, "接收 addrLen 失败") + } + addrBuf, err := utils.ReadBuffer(src, int(addrLen)) + if err != nil { + return errors.Wrap(err, "接收 addrBuf 失败") + } + addr := string(addrBuf) + + // 数据转发 + slog.Info("向目标 " + addr + " 建立连接") + dest, err := net.Dial("tcp", addr) + if err != nil { + return errors.Wrap(err, "连接失败") + } + defer utils.Close(dest) + + slog.Info("开始代理流量 " + src.RemoteAddr().String() + " <-> " + dest.RemoteAddr().String()) + timer := time.Now() + errCh := make(chan error) + go func() { + written, err := io.Copy(dest, src) + if err != nil && !errors.Is(err, net.ErrClosed) { + slog.Error("上行流量代理失败", "err", err) + errCh <- err + return + } else { + slog.Info("上行流量代理结束") + } + slog.Info("上行流量", "bytes", written) + errCh <- nil + }() + go func() { + written, err := io.Copy(src, dest) + if err != nil && !errors.Is(err, net.ErrClosed) { + slog.Error("下行流量代理失败", "err", err) + errCh <- err + return + } else { + slog.Info("下行流量代理结束") + } + slog.Info("下行流量", "bytes", written) + errCh <- nil + }() + <-errCh + slog.Info("代理流量结束", "time", time.Since(timer)) + slog.Info("数据通道结束", "time", time.Since(timerAll)) + return nil +} + +func initEnv() { + err := godotenv.Load() + if err != nil { + slog.Debug("没有本地环境变量文件") + } + + cfg.FrpHost = os.Getenv("FRP_HOST") + + frpCtrlPort, err := strconv.ParseUint(os.Getenv("FRP_CTRL_PORT"), 10, 16) + if err != nil { + panic("环境变量 FRP_CTRL_PORT 的值不合法 " + err.Error()) + } + cfg.FrpCtrlPort = uint16(frpCtrlPort) + if cfg.FrpCtrlPort == 0 { + panic("环境变量 FRP_CTRL_PORT 不能为空") + } + + frpDataPort, err := strconv.ParseUint(os.Getenv("FRP_DATA_PORT"), 10, 16) + if err != nil { + panic("环境变量 FRP_DATA_PORT 的值不合法 " + err.Error()) + } + cfg.FrpDataPort = uint16(frpDataPort) + if cfg.FrpDataPort == 0 { + panic("环境变量 FRP_DATA_PORT 不能为空") + } + + fwdPort, err := strconv.ParseUint(os.Getenv("FWD_PORT"), 10, 16) + if err != nil { + panic("环境变量 FWD_PORT 的值不合法 " + err.Error()) + } + cfg.FwdPort = uint16(fwdPort) + if cfg.FwdPort == 0 { + panic("环境变量 FWD_PORT 不能为空") + } + + cfg.RetryInterval, err = strconv.Atoi(os.Getenv("RETRY_INTERVAL")) + if err != nil { + panic("环境变量 RETRY_INTERVAL 的值不合法 " + err.Error()) + } + if cfg.RetryInterval == 0 { + cfg.RetryInterval = 5 + } +} + +func initLog() { + slog.SetLogLoggerLevel(slog.LevelDebug) +} diff --git a/cmd/client/main.go b/cmd/client/main.go index e9e504c..205cc8e 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -1,211 +1,7 @@ package main -import ( - "bufio" - "encoding/binary" - "fmt" - "io" - "log/slog" - "net" - "os" - "proxy-server/pkg/utils" - "strconv" - "time" - - "github.com/joho/godotenv" - "github.com/pkg/errors" -) - -type Config struct { - FrpHost string - FrpCtrlPort uint16 - FrpDataPort uint16 - FwdPort uint16 - RetryInterval int -} - -var cfg Config - -var frpCtrlAddr string -var frpDataAddr string +import "proxy-server/client" func main() { - - initLog() - initEnv() - - frpCtrlAddr = net.JoinHostPort(cfg.FrpHost, strconv.Itoa(int(cfg.FrpCtrlPort))) - frpDataAddr = net.JoinHostPort(cfg.FrpHost, strconv.Itoa(int(cfg.FrpDataPort))) - - // 建立控制通道 - for { - slog.Info("建立控制通道", "addr", frpCtrlAddr) - err := control() - if err != nil { - slog.Error("建立控制通道失败", err) - slog.Info(fmt.Sprintf("%d 秒后重试", cfg.RetryInterval)) - time.Sleep(time.Duration(cfg.RetryInterval) * time.Second) - } - } -} - -func control() error { - conn, err := net.Dial("tcp", frpCtrlAddr) - if err != nil { - return errors.Wrap(err, "连接失败") - } - defer utils.Close(conn) - - // 请求转发端口 - slog.Info("注册转发端口", "port", cfg.FwdPort) - portBuf := make([]byte, 2) - binary.BigEndian.PutUint16(portBuf, cfg.FwdPort) - _, err = conn.Write(portBuf) - if err != nil { - return errors.Wrap(err, "注册转发端口失败") - } - - // 等待用户连接 - // 读写失败后退出重连,防止后续数据读写顺序错位导致卡死控制通道 - for { - slog.Info("等待用户连接") - reader := bufio.NewReader(conn) - - tagLen, err := utils.ReadByte(reader) - if err != nil { - return errors.Wrap(err, "接收 tagLen 失败") - } - tagBuf, err := utils.ReadBuffer(reader, int(tagLen)) - if err != nil { - return errors.Wrap(err, "接收 tagBuf 失败") - } - - // 建立数据通道 - go func() { - slog.Info("收到用户连接,建立数据通道") - err := data(tagLen, tagBuf) - if err != nil { - slog.Error("建立数据通道失败", err) - } - }() - } -} - -func data(tagLen byte, tagBuf []byte) error { - timerAll := time.Now() - src, err := net.Dial("tcp", frpDataAddr) - if err != nil { - return errors.Wrap(err, "连接失败") - } - defer utils.Close(src) - - // 发送 tag - slog.Info("准备代理流量") - writeBuf := make([]byte, 1+len(tagBuf)) - writeBuf[0] = tagLen - copy(writeBuf[1:], tagBuf) - _, err = src.Write(writeBuf) - if err != nil { - return errors.Wrap(err, "发送 tag 失败") - } - - // 接收目标地址 - slog.Info("接收目标地址") - addrLen, err := utils.ReadByte(src) - if err != nil { - return errors.Wrap(err, "接收 addrLen 失败") - } - addrBuf, err := utils.ReadBuffer(src, int(addrLen)) - if err != nil { - return errors.Wrap(err, "接收 addrBuf 失败") - } - addr := string(addrBuf) - - // 数据转发 - slog.Info("向目标 " + addr + " 建立连接") - dest, err := net.Dial("tcp", addr) - if err != nil { - return errors.Wrap(err, "连接失败") - } - defer utils.Close(dest) - - slog.Info("开始代理流量 " + src.RemoteAddr().String() + " <-> " + dest.RemoteAddr().String()) - timer := time.Now() - errCh := make(chan error) - go func() { - written, err := io.Copy(dest, src) - if err != nil && !errors.Is(err, net.ErrClosed) { - slog.Error("上行流量代理失败", "err", err) - errCh <- err - return - } else { - slog.Info("上行流量代理结束") - } - slog.Info("上行流量", "bytes", written) - errCh <- nil - }() - go func() { - written, err := io.Copy(src, dest) - if err != nil && !errors.Is(err, net.ErrClosed) { - slog.Error("下行流量代理失败", "err", err) - errCh <- err - return - } else { - slog.Info("下行流量代理结束") - } - slog.Info("下行流量", "bytes", written) - errCh <- nil - }() - <-errCh - slog.Info("代理流量结束", "time", time.Since(timer)) - slog.Info("数据通道结束", "time", time.Since(timerAll)) - return nil -} - -func initEnv() { - err := godotenv.Load() - if err != nil { - slog.Debug("没有本地环境变量文件") - } - - cfg.FrpHost = os.Getenv("FRP_HOST") - - frpCtrlPort, err := strconv.ParseUint(os.Getenv("FRP_CTRL_PORT"), 10, 16) - if err != nil { - panic("环境变量 FRP_CTRL_PORT 的值不合法 " + err.Error()) - } - cfg.FrpCtrlPort = uint16(frpCtrlPort) - if cfg.FrpCtrlPort == 0 { - panic("环境变量 FRP_CTRL_PORT 不能为空") - } - - frpDataPort, err := strconv.ParseUint(os.Getenv("FRP_DATA_PORT"), 10, 16) - if err != nil { - panic("环境变量 FRP_DATA_PORT 的值不合法 " + err.Error()) - } - cfg.FrpDataPort = uint16(frpDataPort) - if cfg.FrpDataPort == 0 { - panic("环境变量 FRP_DATA_PORT 不能为空") - } - - fwdPort, err := strconv.ParseUint(os.Getenv("FWD_PORT"), 10, 16) - if err != nil { - panic("环境变量 FWD_PORT 的值不合法 " + err.Error()) - } - cfg.FwdPort = uint16(fwdPort) - if cfg.FwdPort == 0 { - panic("环境变量 FWD_PORT 不能为空") - } - - cfg.RetryInterval, err = strconv.Atoi(os.Getenv("RETRY_INTERVAL")) - if err != nil { - panic("环境变量 RETRY_INTERVAL 的值不合法 " + err.Error()) - } - if cfg.RetryInterval == 0 { - cfg.RetryInterval = 5 - } -} - -func initLog() { - slog.SetLogLoggerLevel(slog.LevelDebug) + client.Start() } diff --git a/server/fwd/service.go b/server/fwd/service.go index 913ff14..5171cf2 100644 --- a/server/fwd/service.go +++ b/server/fwd/service.go @@ -163,14 +163,14 @@ func (s *Service) processCtrlConn(controller net.Conn) { }, }) if err != nil { - slog.Error("代理服务创建失败", err) + slog.Error("代理服务创建失败", "err", err) return } go func() { err := proxy.Run() if err != nil { - slog.Error("代理服务建立失败", err) + slog.Error("代理服务建立失败", "err", err) return } }() @@ -181,13 +181,13 @@ func (s *Service) processCtrlConn(controller net.Conn) { tag := user.Tag() _, err := controller.Write([]byte{byte(len(tag))}) if err != nil { - slog.Error("write error", err) + slog.Error("write error", "err", err) return } _, err = controller.Write([]byte(tag)) slog.Info("已通知客户端建立数据通道") if err != nil { - slog.Error("write error", err) + slog.Error("write error", "err", err) return } s.connMap[tag] = user @@ -201,7 +201,7 @@ func (s *Service) startDataTun(ctx context.Context, errCh chan error) { // 监听端口 lData, err := net.Listen("tcp", ":"+strconv.Itoa(int(dataPort))) if err != nil { - slog.Error("listen error", err) + slog.Error("listen error", "err", err) return } defer utils.Close(lData) @@ -255,12 +255,12 @@ func (s *Service) processDataConn(client net.Conn) { // 读取 tag tagLen, err := utils.ReadByte(client) if err != nil { - slog.Error("read error", err) + slog.Error("read error", "err", err) return } tagBuf, err := utils.ReadBuffer(client, int(tagLen)) if err != nil { - slog.Error("read error", err) + slog.Error("read error", "err", err) return } tag := string(tagBuf) @@ -280,12 +280,12 @@ func (s *Service) processDataConn(client net.Conn) { // 写入目标地址 _, err = client.Write([]byte{byte(len(data.Dest))}) if err != nil { - slog.Error("写入目标地址失败", err) + slog.Error("写入目标地址失败", "err", err) return } _, err = client.Write([]byte(data.Dest)) if err != nil { - slog.Error("写入目标地址失败", err) + slog.Error("写入目标地址失败", "err", err) return } @@ -295,14 +295,14 @@ func (s *Service) processDataConn(client net.Conn) { go func() { _, err := io.Copy(client, user) if err != nil { - slog.Error("processDataConn error c2u", err) + slog.Error("processDataConn error c2u", "err", err) } errCh <- err }() go func() { _, err := io.Copy(user, client) if err != nil { - slog.Error("processDataConn error u2c", err) + slog.Error("processDataConn error u2c", "err", err) } errCh <- err }() @@ -366,7 +366,8 @@ func (a *NoAuthAuthenticator) Authenticate(ctx context.Context, reader io.Reader } // 检查权限是否过期 - timeout := uint(channel.Expiration.Sub(time.Now()).Seconds()) + timeout := channel.Expiration.Sub(time.Now()).Seconds() + slog.Info("用户剩余时间", "timeout", timeout) if timeout <= 0 { return nil, errors.New("noAuth 权限已过期") } @@ -374,7 +375,7 @@ func (a *NoAuthAuthenticator) Authenticate(ctx context.Context, reader io.Reader return &socks5.AuthContext{ Method: socks5.NoAuth, - Timeout: timeout, + Timeout: uint(timeout), Payload: nil, }, nil } @@ -443,7 +444,8 @@ func (a *UserPassAuthenticator) Authenticate(ctx context.Context, reader io.Read } // 检查权限是否过期 - timeout := uint(channel.Expiration.Sub(time.Now()).Seconds()) + timeout := channel.Expiration.Sub(time.Now()).Seconds() + slog.Info("用户剩余时间", "timeout", timeout) if timeout <= 0 { return nil, errors.New("权限已过期") } @@ -484,13 +486,13 @@ func (a *UserPassAuthenticator) Authenticate(ctx context.Context, reader io.Read // 响应认证成功 _, err = writer.Write([]byte{socks5.AuthVersion, socks5.AuthSuccess}) if err != nil { - slog.Error("响应认证失败", err) + slog.Error("响应认证失败", "err", err) return nil, err } return &socks5.AuthContext{ Method: socks5.UserPassAuth, - Timeout: 300, // todo + Timeout: uint(timeout), Payload: nil, }, nil } diff --git a/server/fwd/service_test.go b/server/fwd/service_test.go new file mode 100644 index 0000000..f80c5ab --- /dev/null +++ b/server/fwd/service_test.go @@ -0,0 +1,294 @@ +package fwd + +import ( + "bytes" + "context" + "io" + "net" + "proxy-server/pkg/utils" + "proxy-server/server/pkg/socks5" + "reflect" + "testing" +) + +func TestNew(t *testing.T) { + type args struct { + config *Config + } + tests := []struct { + name string + args args + want *Service + }{ + // TODO: Add test cases. + { + name: "server config nil", + args: args{ + config: nil, + }, + want: &Service{ + Config: &Config{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := New(tt.args.config); !reflect.DeepEqual(got, tt.want) { + t.Errorf("New() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNoAuthAuthenticator_Authenticate(t *testing.T) { + type args struct { + ctx context.Context + reader io.Reader + } + tests := []struct { + name string + args args + wantWriter string + want *socks5.AuthContext + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &NoAuthAuthenticator{} + writer := &bytes.Buffer{} + got, err := a.Authenticate(tt.args.ctx, tt.args.reader, writer) + if (err != nil) != tt.wantErr { + t.Errorf("Authenticate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotWriter := writer.String(); gotWriter != tt.wantWriter { + t.Errorf("Authenticate() gotWriter = %v, want %v", gotWriter, tt.wantWriter) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Authenticate() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNoAuthAuthenticator_Method(t *testing.T) { + tests := []struct { + name string + want socks5.AuthMethod + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &NoAuthAuthenticator{} + if got := a.Method(); got != tt.want { + t.Errorf("Method() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestService_Run(t *testing.T) { + type fields struct { + Config *Config + connMap map[string]socks5.ProxyData + ctrlConnWg utils.CountWaitGroup + dataConnWg utils.CountWaitGroup + } + type args struct { + ctx context.Context + errCh chan error + } + tests := []struct { + name string + fields fields + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Service{ + Config: tt.fields.Config, + connMap: tt.fields.connMap, + ctrlConnWg: tt.fields.ctrlConnWg, + dataConnWg: tt.fields.dataConnWg, + } + s.Run(tt.args.ctx, tt.args.errCh) + }) + } +} + +func TestService_processCtrlConn(t *testing.T) { + type fields struct { + Config *Config + connMap map[string]socks5.ProxyData + ctrlConnWg utils.CountWaitGroup + dataConnWg utils.CountWaitGroup + } + type args struct { + controller net.Conn + } + tests := []struct { + name string + fields fields + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Service{ + Config: tt.fields.Config, + connMap: tt.fields.connMap, + ctrlConnWg: tt.fields.ctrlConnWg, + dataConnWg: tt.fields.dataConnWg, + } + s.processCtrlConn(tt.args.controller) + }) + } +} + +func TestService_processDataConn(t *testing.T) { + type fields struct { + Config *Config + connMap map[string]socks5.ProxyData + ctrlConnWg utils.CountWaitGroup + dataConnWg utils.CountWaitGroup + } + type args struct { + client net.Conn + } + tests := []struct { + name string + fields fields + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Service{ + Config: tt.fields.Config, + connMap: tt.fields.connMap, + ctrlConnWg: tt.fields.ctrlConnWg, + dataConnWg: tt.fields.dataConnWg, + } + s.processDataConn(tt.args.client) + }) + } +} + +func TestService_startCtrlTun(t *testing.T) { + type fields struct { + Config *Config + connMap map[string]socks5.ProxyData + ctrlConnWg utils.CountWaitGroup + dataConnWg utils.CountWaitGroup + } + type args struct { + ctx context.Context + errCh chan error + } + tests := []struct { + name string + fields fields + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Service{ + Config: tt.fields.Config, + connMap: tt.fields.connMap, + ctrlConnWg: tt.fields.ctrlConnWg, + dataConnWg: tt.fields.dataConnWg, + } + s.startCtrlTun(tt.args.ctx, tt.args.errCh) + }) + } +} + +func TestService_startDataTun(t *testing.T) { + type fields struct { + Config *Config + connMap map[string]socks5.ProxyData + ctrlConnWg utils.CountWaitGroup + dataConnWg utils.CountWaitGroup + } + type args struct { + ctx context.Context + errCh chan error + } + tests := []struct { + name string + fields fields + args args + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := &Service{ + Config: tt.fields.Config, + connMap: tt.fields.connMap, + ctrlConnWg: tt.fields.ctrlConnWg, + dataConnWg: tt.fields.dataConnWg, + } + s.startDataTun(tt.args.ctx, tt.args.errCh) + }) + } +} + +func TestUserPassAuthenticator_Authenticate(t *testing.T) { + type args struct { + ctx context.Context + reader io.Reader + } + tests := []struct { + name string + args args + wantWriter string + want *socks5.AuthContext + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &UserPassAuthenticator{} + writer := &bytes.Buffer{} + got, err := a.Authenticate(tt.args.ctx, tt.args.reader, writer) + if (err != nil) != tt.wantErr { + t.Errorf("Authenticate() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotWriter := writer.String(); gotWriter != tt.wantWriter { + t.Errorf("Authenticate() gotWriter = %v, want %v", gotWriter, tt.wantWriter) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Authenticate() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUserPassAuthenticator_Method(t *testing.T) { + tests := []struct { + name string + want socks5.AuthMethod + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &UserPassAuthenticator{} + if got := a.Method(); got != tt.want { + t.Errorf("Method() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/test/server/fwd/auth_test.go b/test/server/fwd/auth_test.go new file mode 100644 index 0000000..85a1476 --- /dev/null +++ b/test/server/fwd/auth_test.go @@ -0,0 +1,40 @@ +package fwd + +import ( + "net" + "proxy-server/server/pkg/socks5" + "testing" +) + +func BenchmarkNoAuth(b *testing.B) { + for i := 0; i < b.N; i++ { + } +} + +func BenchmarkUserPassAuth(b *testing.B) { + + for i := 0; i < b.N; i++ { + + } +} + +func fakeRequest() { + + conn, err := net.Dial("tcp", "localhost:20001") + if err != nil { + panic(err) + } + + // 发送认证请求 + _, err = conn.Write([]byte{socks5.SocksVersion, byte(1), byte(socks5.NoAuth)}) + if err != nil { + panic(err) + } + + // 忽略返回 + _, err = conn.Read(make([]byte, 2)) + if err != nil { + panic(err) + } + +}