package socket5 import ( "errors" "fmt" "go-socket5-proxy/helper" "io" "log" "net" ) type Server interface { Run() error } type Socket5Server struct { Port int64 IP string } func (s *Socket5Server) Run() error { address := fmt.Sprintf("%s:%d", s.IP, s.Port) fmt.Printf("%s:%d \n", s.IP, s.Port) listen, err := helper.CreateListen(address) if err != nil { log.Fatal(err) return err } for { conn, err := listen.Accept() if err != nil { log.Printf("连接失败:%s: %s", conn.RemoteAddr(), err) } go func() { defer conn.Close() err = handleConnection(conn) if err != nil { //log.Printf("处理连接 handleConnection %s: %s", conn.RemoteAddr(), err) } }() } } // 处理连接 handleConnection func handleConnection(conn net.Conn) error { //协商过程 if err := auth(conn); err != nil { return err } //请求过程 targetConn, err := request(conn) if err != nil { return err } if targetConn == nil { return nil } //转发过程 return forward(conn, targetConn) } func forward(conn net.Conn, targetConn net.Conn) error { defer targetConn.Close() go io.Copy(targetConn, conn) _, err := io.Copy(conn, targetConn) return err } func request(conn net.Conn) (net.Conn, error) { message, err := NewClientRequestMessage(conn) if err != nil { return nil, err } //检查命令是否支持 if message.CMD != CmdConnect { return nil, WriteRequestFailureMessage(conn, ReplyCommandNotSupported) } //ipv6 if message.AddressType == TypeIPV6 { return nil, WriteRequestFailureMessage(conn, ReplyAddressTypeNotSupported) } //请求访问目标服务器 addres := fmt.Sprintf("%s:%d", message.Address, message.Port) //fmt.Printf("请求访问目标服务器:%v\n", message.AddressType) targetConn, err := net.Dial("tcp", addres) if err != nil { return nil, WriteRequestFailureMessage(conn, ReplyConnectionRefused) } //发送成功 addrValue := targetConn.LocalAddr() addr := addrValue.(*net.TCPAddr) if targetConn == nil { fmt.Printf("targetConn is nil :" + addr.IP.String()) } return targetConn, WriteRequestSuccessMessage(conn, addr.IP, uint16(addr.Port)) } func auth(conn net.Conn) error { client, err := NewClientAuthMessage(conn) if err != nil { return err } //log.Println(client.Version, client.NMethods, client.Methods) // 是否支持 no-auth var accept_table bool for _, method := range client.Methods { if method == Method_NO_AUTH { accept_table = true } } if !accept_table { NewServerAuthMessage(conn, Method_NO_ACCEPT_TABLE) return errors.New("方法不支持 not auth") } return NewServerAuthMessage(conn, Method_NO_AUTH) }