From 8cb9e9bf44af377ed0bee45893c51ef1e2d76d4f Mon Sep 17 00:00:00 2001 From: hang666 <44329474+hang666@users.noreply.github.com> Date: Mon, 5 Dec 2022 15:59:57 +0800 Subject: [PATCH] v0.1.1 Update Specify out local address. Fix whitelist validation. --- README.md | 13 ++++++-- config.yaml.example | 18 ++++++----- server/config.go | 3 +- server/handle.go | 19 ++---------- server/s5/request.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ server/server.go | 5 +-- server/util.go | 20 ++++++++++++ 7 files changed, 121 insertions(+), 30 deletions(-) create mode 100644 server/s5/request.go create mode 100644 server/util.go diff --git a/README.md b/README.md index 02bb544..0a92a0f 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,22 @@ This software supports Windows/MacOS/Centos/Debian/Ubuntu and, in theory, all Linux. - - Support Multiple Validation - - Support for IP address whitelisting -The configuration file using YAML language. +Configuration file using YAML language. Please fill in the template according to "config.yaml.example", and save it as "config.yaml". You can also use the "--config" flag to customize the path to the config file. + +## Features + + - Full TCP/UDP support + - Multiple validation + - IP address whitelisting + - Specify out local address + + ## Install Script: ```bash diff --git a/config.yaml.example b/config.yaml.example index 7fa2d00..0c42531 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -1,11 +1,13 @@ accounts: - - username: "test" - password: "test123456" - bind_address: "0.0.0.0:8080" - req_address: "" - tcp_timeout: 60 - udp_timeout: 60 - whitelist: + - username: "test" # auth username + password: "test123456" # auth password + bind_address: "0.0.0.0:8080" # listen bind address + port + udp_bind_ip: "127.0.0.1" # udp bind ip + out_address: "192.168.100.165" # specify out local address + tcp_timeout: 60 # tcp timeout + udp_timeout: 60 # udp timeout + whitelist: # whitelist - "192.168.100.1" - "127.0.0.1" - - bind_address: "0.0.0.0:8081" + - bind_address: "0.0.0.0:8081" # bind 2 + out_address: "" # auto out address diff --git a/server/config.go b/server/config.go index 93c312d..4ff913f 100644 --- a/server/config.go +++ b/server/config.go @@ -15,7 +15,8 @@ type AccountStruct struct { Username string `yaml:"username" mapstructure:"username"` Password string `yaml:"password" mapstructure:"password"` BindAddress string `yaml:"bind_address" mapstructure:"bind_address"` - ReqAddress string `yaml:"req_address" mapstructure:"req_address"` + OutAddress string `yaml:"out_address" mapstructure:"out_address"` + UDPBindIP string `yaml:"udp_bind_ip" mapstructure:"udp_bind_ip"` Whitelist []string `yaml:"whitelist" mapstructure:"whitelist"` TCPTimeout int `yaml:"tcp_timeout" mapstructure:"tcp_timeout"` UDPTimeout int `yaml:"udp_timeout" mapstructure:"udp_timeout"` diff --git a/server/handle.go b/server/handle.go index 2ef94b9..a4226f8 100644 --- a/server/handle.go +++ b/server/handle.go @@ -8,26 +8,13 @@ import ( "strings" "time" + "github.com/hang666/s5light/server/s5" "github.com/txthinking/socks5" ) type DefaultHandle struct { whitelistMap WhitelistMapType -} - -func checkIsWhitelisted(address string, whitelistMap WhitelistMapType) bool { - //log.Printf("client come in: %s", address) - w_map := whitelistMap - if len(w_map) == 0 { - return true - } - var ok bool - if strings.Contains(address, ":") { - _, ok = w_map[strings.Split(address, ":")[0]] - } else { - _, ok = w_map[address] - } - return ok + outAddress string } func (h *DefaultHandle) TCPHandle(s *socks5.Server, c *net.TCPConn, r *socks5.Request) error { @@ -35,7 +22,7 @@ func (h *DefaultHandle) TCPHandle(s *socks5.Server, c *net.TCPConn, r *socks5.Re return fmt.Errorf("%s is not whitelisted", c.RemoteAddr().String()) } if r.Cmd == socks5.CmdConnect { - rc, err := r.Connect(c) + rc, err := s5.Connect(c, r, h.outAddress) if err != nil { return err } diff --git a/server/s5/request.go b/server/s5/request.go new file mode 100644 index 0000000..c254ec6 --- /dev/null +++ b/server/s5/request.go @@ -0,0 +1,73 @@ +package s5 + +import ( + "io" + "log" + "net" + + "github.com/txthinking/socks5" +) + +// Connect remote conn which u want to connect with your dialer +// Error or OK both replied. +func Connect(w io.Writer, r *socks5.Request, outAddress string) (*net.TCPConn, error) { + if socks5.Debug { + log.Println("Call:", r.Address()) + } + var tmp *net.TCPConn + var err error + + tcpaddr, err := net.ResolveTCPAddr("tcp", r.Address()) + if err != nil { + var p *socks5.Reply + if r.Atyp == socks5.ATYPIPv4 || r.Atyp == socks5.ATYPDomain { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00}) + } else { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00}) + } + if _, err := p.WriteTo(w); err != nil { + return nil, err + } + return nil, err + } + if outAddress != "" { + localAddr, _ := net.ResolveTCPAddr("tcp", outAddress+":0") + + tmp, err = socks5.Dial.DialTCP("tcp", localAddr, tcpaddr) + + } else { + tmp, err = socks5.Dial.DialTCP("tcp", nil, tcpaddr) + } + if err != nil { + var p *socks5.Reply + if r.Atyp == socks5.ATYPIPv4 || r.Atyp == socks5.ATYPDomain { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00}) + } else { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00}) + } + if _, err := p.WriteTo(w); err != nil { + return nil, err + } + return nil, err + } + rc := tmp + a, addr, port, err := socks5.ParseAddress(rc.LocalAddr().String()) + if err != nil { + var p *socks5.Reply + if r.Atyp == socks5.ATYPIPv4 || r.Atyp == socks5.ATYPDomain { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00}) + } else { + p = socks5.NewReply(socks5.RepHostUnreachable, socks5.ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00}) + } + if _, err := p.WriteTo(w); err != nil { + return nil, err + } + return nil, err + } + p := socks5.NewReply(socks5.RepSuccess, a, addr, port) + if _, err := p.WriteTo(w); err != nil { + return nil, err + } + + return rc, nil +} diff --git a/server/server.go b/server/server.go index bd41fc0..b9dc73b 100644 --- a/server/server.go +++ b/server/server.go @@ -19,11 +19,12 @@ func listenAndServe() { wg.Add(1) go func(acc *AccountStruct) { log.Printf("Server listening on %s", acc.BindAddress) - server, err := socks5.NewClassicServer(acc.BindAddress, acc.ReqAddress, acc.Username, acc.Password, acc.TCPTimeout, acc.UDPTimeout) + socks5.Debug = true + server, err := socks5.NewClassicServer(acc.BindAddress, acc.UDPBindIP, acc.Username, acc.Password, acc.TCPTimeout, acc.UDPTimeout) if err != nil { log.Panicln(err) } - server.ListenAndServe(&DefaultHandle{acc.WhitelistMap}) + server.ListenAndServe(&DefaultHandle{acc.WhitelistMap, acc.OutAddress}) wg.Done() }(acc) } diff --git a/server/util.go b/server/util.go new file mode 100644 index 0000000..d3fca29 --- /dev/null +++ b/server/util.go @@ -0,0 +1,20 @@ +package server + +import ( + "net" +) + +func checkIsWhitelisted(address string, whitelistMap WhitelistMapType) bool { + //log.Printf("client come in: %s", address) + w_map := whitelistMap + if len(w_map) == 0 { + return true + } + var ok bool + addr, _, err := net.SplitHostPort(address) + if err != nil { + addr = address + } + _, ok = w_map[addr] + return ok +}