diff --git a/main.go b/main.go index 04d5275..0cdbe45 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,10 @@ package main import ( - "encoding/binary" - "errors" - "fmt" - "io" "log" - "net" "os" "os/signal" "proxy_socks5/ui" - "sync" "syscall" "time" ) @@ -18,7 +12,6 @@ import ( const ( name = "Socks5" version = "v1.0.0" - port = "1080" ) func main() { @@ -27,16 +20,12 @@ func main() { log.Printf("panic: %v\n", p) } }() - exitCh := make(chan os.Signal, 10) signal.Notify(exitCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) //syscall.SIGUSR1, syscall.SIGUSR2) - go run() - gui := ui.New( ui.Version(version), ui.Name(name), - ui.Port(port), ui.OnClose(func() { log.Printf("gui OnClose callback") }), @@ -45,167 +34,7 @@ func main() { os.Exit(func() (code int) { code = gui.Run(exitCh) log.Printf("exit code: %v", code) - time.Sleep(1 * time.Second) + time.Sleep(1 * time.Millisecond) return }()) } - -func run() { - server, err := net.Listen("tcp", ":"+port) - if err != nil { - log.Printf("Listen failed: %v\n", err) - return - } - - for { - client, err := server.Accept() - if err != nil { - log.Printf("Accept failed: %v", err) - continue - } - go process(client) - } -} - -func process(client net.Conn) { - if err := Socks5Auth(client); err != nil { - log.Println("auth error:", err) - client.Close() - return - } - - target, err := Socks5Connect(client) - if err != nil { - log.Println("connect error:", err) - client.Close() - return - } - - Socks5Forward(client, target) -} - -func Socks5Auth(client net.Conn) (err error) { - buf := make([]byte, 256) - - // 读取 VER 和 NMETHODS - n, err := io.ReadFull(client, buf[:2]) - if n != 2 { - return errors.New("reading header: " + err.Error()) - } - - ver, nMethods := int(buf[0]), int(buf[1]) - if ver != 5 { - return errors.New("invalid version") - } - - // 读取 METHODS 列表 - n, err = io.ReadFull(client, buf[:nMethods]) - if n != nMethods { - return errors.New("reading methods: " + err.Error()) - } - - //无需认证 - n, err = client.Write([]byte{0x05, 0x00}) - if n != 2 || err != nil { - return errors.New("write rsp: " + err.Error()) - } - - return nil -} - -func Socks5Connect(client net.Conn) (net.Conn, error) { - buf := make([]byte, 256) - - n, err := io.ReadFull(client, buf[:4]) - if n != 4 { - return nil, errors.New("read header: " + err.Error()) - } - - ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3] - if ver != 5 || cmd != 1 { - return nil, errors.New("invalid ver/cmd") - } - - addr := "" - switch atyp { - case 1: - n, err = io.ReadFull(client, buf[:4]) - if n != 4 { - return nil, errors.New("invalid IPv4: " + err.Error()) - } - addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]) - - case 3: - n, err = io.ReadFull(client, buf[:1]) - if n != 1 { - return nil, errors.New("invalid hostname: " + err.Error()) - } - addrLen := int(buf[0]) - - n, err = io.ReadFull(client, buf[:addrLen]) - if n != addrLen { - return nil, errors.New("invalid hostname: " + err.Error()) - } - addr = string(buf[:addrLen]) - - case 4: - return nil, errors.New("IPv6: no supported yet") - - default: - return nil, errors.New("invalid atyp") - } - - n, err = io.ReadFull(client, buf[:2]) - if n != 2 { - return nil, errors.New("read port: " + err.Error()) - } - port := binary.BigEndian.Uint16(buf[:2]) - - destAddrPort := fmt.Sprintf("%s:%d", addr, port) - dest, err := net.Dial("tcp", destAddrPort) - if err != nil { - return nil, errors.New("dial dst: " + err.Error()) - } - - _, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}) - if err != nil { - dest.Close() - return nil, errors.New("write rsp: " + err.Error()) - } - - return dest, nil -} - -// func Socks5Forward(client, target net.Conn) { -// forward := func(src, dest net.Conn) { -// defer src.Close() -// defer dest.Close() -// io.Copy(src, dest) -// } -// go forward(client, target) -// go forward(target, client) -// } -func Socks5Forward(left, right net.Conn) error { - var err, err1 error - var wg sync.WaitGroup - var wait = 5 * time.Second - wg.Add(1) - go func() { - defer wg.Done() - _, err1 = io.Copy(right, left) - right.SetReadDeadline(time.Now().Add(wait)) - }() - _, err = io.Copy(left, right) - left.SetReadDeadline(time.Now().Add(wait)) - wg.Wait() - - if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { - return err - } - - if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { - return err1 - } - - return nil -} diff --git a/service/service.go b/service/service.go new file mode 100644 index 0000000..c7edd62 --- /dev/null +++ b/service/service.go @@ -0,0 +1,173 @@ +package service + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "log" + "net" + "os" + "sync" + "time" +) + +func RunServe(port string) { + server, err := net.Listen("tcp", ":"+port) + if err != nil { + log.Printf("Listen failed: %v\n", err) + return + } + + for { + client, err := server.Accept() + if err != nil { + log.Printf("Accept failed: %v", err) + continue + } + go process(client) + } +} + +func process(client net.Conn) { + if err := Socks5Auth(client); err != nil { + log.Println("auth error:", err) + client.Close() + return + } + + target, err := Socks5Connect(client) + if err != nil { + log.Println("connect error:", err) + client.Close() + return + } + + Socks5Forward(client, target) +} + +func Socks5Auth(client net.Conn) (err error) { + buf := make([]byte, 256) + + // 读取 VER 和 NMETHODS + n, err := io.ReadFull(client, buf[:2]) + if n != 2 { + return errors.New("reading header: " + err.Error()) + } + + ver, nMethods := int(buf[0]), int(buf[1]) + if ver != 5 { + return errors.New("invalid version") + } + + // 读取 METHODS 列表 + n, err = io.ReadFull(client, buf[:nMethods]) + if n != nMethods { + return errors.New("reading methods: " + err.Error()) + } + + //无需认证 + n, err = client.Write([]byte{0x05, 0x00}) + if n != 2 || err != nil { + return errors.New("write rsp: " + err.Error()) + } + + return nil +} + +func Socks5Connect(client net.Conn) (net.Conn, error) { + buf := make([]byte, 256) + + n, err := io.ReadFull(client, buf[:4]) + if n != 4 { + return nil, errors.New("read header: " + err.Error()) + } + + ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3] + if ver != 5 || cmd != 1 { + return nil, errors.New("invalid ver/cmd") + } + + addr := "" + switch atyp { + case 1: + n, err = io.ReadFull(client, buf[:4]) + if n != 4 { + return nil, errors.New("invalid IPv4: " + err.Error()) + } + addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]) + + case 3: + n, err = io.ReadFull(client, buf[:1]) + if n != 1 { + return nil, errors.New("invalid hostname: " + err.Error()) + } + addrLen := int(buf[0]) + + n, err = io.ReadFull(client, buf[:addrLen]) + if n != addrLen { + return nil, errors.New("invalid hostname: " + err.Error()) + } + addr = string(buf[:addrLen]) + + case 4: + return nil, errors.New("IPv6: no supported yet") + + default: + return nil, errors.New("invalid atyp") + } + + n, err = io.ReadFull(client, buf[:2]) + if n != 2 { + return nil, errors.New("read port: " + err.Error()) + } + port := binary.BigEndian.Uint16(buf[:2]) + + destAddrPort := fmt.Sprintf("%s:%d", addr, port) + dest, err := net.Dial("tcp", destAddrPort) + if err != nil { + return nil, errors.New("dial dst: " + err.Error()) + } + + _, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}) + if err != nil { + dest.Close() + return nil, errors.New("write rsp: " + err.Error()) + } + + return dest, nil +} + +// func Socks5Forward(client, target net.Conn) { +// forward := func(src, dest net.Conn) { +// defer src.Close() +// defer dest.Close() +// io.Copy(src, dest) +// } +// go forward(client, target) +// go forward(target, client) +// } +func Socks5Forward(left, right net.Conn) error { + var err, err1 error + var wg sync.WaitGroup + var wait = 5 * time.Second + wg.Add(1) + go func() { + defer wg.Done() + _, err1 = io.Copy(right, left) + right.SetReadDeadline(time.Now().Add(wait)) + }() + _, err = io.Copy(left, right) + left.SetReadDeadline(time.Now().Add(wait)) + wg.Wait() + + if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { + return err + } + + if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { + return err1 + } + + return nil +} diff --git a/ui/ui.go b/ui/ui.go index 8481bab..da1a9ac 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -8,7 +8,6 @@ import ( type Options struct { Name string Version string - Port string OnClose func() } @@ -41,11 +40,6 @@ func Name(n string) Option { o.Name = n } } -func Port(p string) Option { - return func(o *Options) { - o.Port = p - } -} // OnClose 关闭窗口事件 func OnClose(f func()) Option { diff --git a/ui/ui_realization.go b/ui/ui_realization.go index 4662e58..7a4e61b 100644 --- a/ui/ui_realization.go +++ b/ui/ui_realization.go @@ -3,6 +3,9 @@ package ui import ( "fmt" "os" + "proxy_socks5/service" + "regexp" + "strconv" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" @@ -10,6 +13,8 @@ import ( "fyne.io/fyne/v2/widget" ) +const reg = "^[0-9]*[1-9][0-9]*$" + type UI struct { Options *Options mw *fyne.Window @@ -28,13 +33,34 @@ func New(op ...Option) GUIApp { a := app.New() w := a.NewWindow(fmt.Sprintf("%v %v", opts.Name, opts.Version)) - lable1 := widget.NewLabel(fmt.Sprintf("Listening at %v", opts.Port)) - lable2 := widget.NewLabel("Running") + var port string + label := widget.NewLabel("") + label.Hidden = true + input := widget.NewEntry() + input.SetPlaceHolder("Please Input The Port...") w.SetContent(container.NewVBox( - lable1, - lable2, + label, + input, + widget.NewButton("Listen", func() { + port = input.Text + r, _ := regexp.Compile(reg) + if r.MatchString(port) { //是数字 + i, _ := strconv.ParseInt(port, 10, 64) + if 1 < 0 || i > 65535 { + port = "1080" + } + } else { //否则 + port = "1080" + } + input.Hidden = true + label.Hidden = false + label.TextStyle.Bold = true + label.SetText(fmt.Sprintf("Listening at %v Succeed!!!", port)) + service.RunServe(port) + }), )) - w.Resize(fyne.NewSize(240, 120)) + + w.Resize(fyne.NewSize(240, 100)) return &UI{ Options: opts,