├── LICENSE ├── README.md ├── event.go ├── go.mod ├── main.go ├── protocol.go ├── request.go ├── server.go ├── tcp_protocol.go ├── udp_exchange.go └── udp_protocol.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 jqqjj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # socks5 2 | socks5 proxy server builds with go/golang 3 | 4 | ### Features 5 | * Both TCP and UDP supported 6 | * "No Auth" authentication supported 7 | * User/Password authentication supported 8 | 9 | ## Install 10 | ``` 11 | $ go install github.com/jqqjj/socks5@master 12 | ``` 13 | 14 | ## Usage 15 | * -p 16 | * port on listen (default 1080) 17 | * -user (option) 18 | * username 19 | * -pwd (option) 20 | * password 21 | 22 | -------------------------------------------------------------------------------- /event.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net" 4 | 5 | type OnConnectedHandle func(network, address string, port int) 6 | type OnStartedHandle func(conn *net.TCPListener) 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jqqjj/socks5 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "net" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | var ( 12 | port int 13 | 14 | username string 15 | password string 16 | ) 17 | 18 | func init() { 19 | flag.StringVar(&username, "user", "", "username") 20 | flag.StringVar(&password, "pwd", "", "password") 21 | flag.IntVar(&port, "p", 1080, "port on listen, must be greater than 0") 22 | flag.Parse() 23 | } 24 | 25 | func main() { 26 | if port <= 0 { 27 | flag.Usage() 28 | os.Exit(1) 29 | } 30 | var serverAddr *net.TCPAddr 31 | if addr, err := net.ResolveTCPAddr("tcp", ":"+strconv.Itoa(port)); err != nil { 32 | fmt.Println(err.Error()) 33 | os.Exit(1) 34 | } else { 35 | serverAddr = addr 36 | } 37 | 38 | server := NewServer() 39 | server.EnableUDP() 40 | server.OnStarted(func(listener *net.TCPListener) { 41 | fmt.Println("start server on", listener.Addr().String()) 42 | }) 43 | server.OnConnected(func(network, address string, port int) { 44 | fmt.Println("["+network+"]connect to:", address+":"+strconv.Itoa(port)) 45 | }) 46 | if username != "" || password != "" { 47 | server.SetAuthHandle(handlerAuth) 48 | } 49 | if err := server.Run(serverAddr); err != nil { 50 | fmt.Println("Run socks5 server error:", err.Error()) 51 | os.Exit(1) 52 | } 53 | 54 | fmt.Println("Socks5 server normal exit.") 55 | os.Exit(0) 56 | } 57 | 58 | func handlerAuth(u, p string) bool { 59 | return u == username && p == password 60 | } 61 | -------------------------------------------------------------------------------- /protocol.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const ( 4 | Version byte = 0x05 5 | 6 | MethodNoAuth byte = 0x00 7 | MethodAuth byte = 0x02 8 | MethodNone byte = 0xFF 9 | 10 | CmdConnect byte = 0x01 11 | CmdUdpAssociate byte = 0x03 12 | 13 | ATYPIPv4 byte = 0x01 14 | ATYPDomain byte = 0x03 15 | ATYPIPv6 byte = 0x04 16 | ) 17 | -------------------------------------------------------------------------------- /request.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "net" 6 | "time" 7 | ) 8 | 9 | type Request struct { 10 | tcpGram TCPProtocol 11 | udpGram UDPProtocol 12 | 13 | ClientConn *net.TCPConn 14 | RemoteConn *net.TCPConn 15 | 16 | UDPConn *net.UDPConn 17 | 18 | server *server 19 | } 20 | 21 | type requestList struct { 22 | prev *requestList 23 | data Request 24 | next *requestList 25 | } 26 | 27 | func (r *Request) Close() error { 28 | var err error 29 | if r.ClientConn != nil { 30 | er := r.ClientConn.Close() 31 | if er != nil { 32 | err = er 33 | } 34 | } 35 | if r.RemoteConn != nil { 36 | er := r.RemoteConn.Close() 37 | if er != nil { 38 | err = er 39 | } 40 | } 41 | if r.UDPConn != nil { 42 | er := r.UDPConn.Close() 43 | if er != nil { 44 | err = er 45 | } 46 | } 47 | return err 48 | } 49 | func (r *Request) Process() { 50 | if err := r.tcpGram.handshake(r.ClientConn); err != nil { 51 | return 52 | } 53 | 54 | if !r.tcpGram.viaUDP { //tcp 55 | //answer bind addr 56 | if conn, err := net.DialTimeout("tcp", r.tcpGram.networkString(), time.Second*time.Duration(r.server.writeTimeoutSecond)); err != nil { 57 | _, _ = r.ClientConn.Write([]byte{Version, 0x04, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 58 | return 59 | } else { 60 | r.RemoteConn = conn.(*net.TCPConn) 61 | } 62 | 63 | bindIP := r.ClientConn.LocalAddr().(*net.TCPAddr).IP 64 | res := make([]byte, 0, 22) 65 | if ip := bindIP.To4(); ip != nil { 66 | //IPv4, len is 4 67 | res = append(res, []byte{Version, 0x00, 0x00, ATYPIPv4}...) 68 | res = append(res, ip...) 69 | } else { 70 | //IPv6, len is 16 71 | res = append(res, []byte{Version, 0x00, 0x00, ATYPIPv6}...) 72 | res = append(res, bindIP...) 73 | } 74 | 75 | portByte := [2]byte{} 76 | binary.BigEndian.PutUint16(portByte[:], uint16(r.ClientConn.LocalAddr().(*net.TCPAddr).Port)) 77 | res = append(res, portByte[:]...) 78 | if _, err := r.ClientConn.Write(res); err != nil { 79 | return 80 | } 81 | 82 | r.transformTCP() 83 | } else { 84 | //bind UDP addr and answer 85 | if !r.server.enableUDP { 86 | _, _ = r.ClientConn.Write([]byte{Version, 0x07, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 87 | return 88 | } 89 | //Listen on UDP 90 | if udpAddr, err := net.ResolveUDPAddr("udp", ":0"); err != nil { 91 | _, _ = r.ClientConn.Write([]byte{Version, 0x01, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 92 | return 93 | } else { 94 | if udpConn, err := net.ListenUDP("udp", udpAddr); err != nil { 95 | _, _ = r.ClientConn.Write([]byte{Version, 0x01, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 96 | return 97 | } else { 98 | r.UDPConn = udpConn 99 | } 100 | } 101 | 102 | bindIP := r.ClientConn.LocalAddr().(*net.TCPAddr).IP 103 | res := make([]byte, 0, 22) 104 | if ip := bindIP.To4(); ip != nil { 105 | //IPv4, len is 4 106 | res = append(res, []byte{Version, 0x00, 0x00, ATYPIPv4}...) 107 | res = append(res, ip...) 108 | } else { 109 | //IPv6, len is 16 110 | res = append(res, []byte{Version, 0x00, 0x00, ATYPIPv6}...) 111 | res = append(res, bindIP...) 112 | } 113 | 114 | portByte := [2]byte{} 115 | binary.BigEndian.PutUint16(portByte[:], uint16(r.UDPConn.LocalAddr().(*net.UDPAddr).Port)) 116 | res = append(res, portByte[:]...) 117 | if _, err := r.ClientConn.Write(res); err != nil { 118 | return 119 | } 120 | 121 | if r.tcpGram.ip.IsGlobalUnicast() && r.tcpGram.port > 0 { 122 | r.udpGram.clientAddr = &net.UDPAddr{IP: r.tcpGram.ip, Port: r.tcpGram.port} 123 | } 124 | 125 | r.transformUDP() 126 | } 127 | } 128 | 129 | func (r *Request) transformTCP() { 130 | if r.server.onConnectedHandle != nil { 131 | var target string 132 | switch r.tcpGram.atyp { 133 | case ATYPIPv4: 134 | target = r.tcpGram.ip.String() 135 | case ATYPIPv6: 136 | target = r.tcpGram.ip.String() 137 | case ATYPDomain: 138 | target = r.tcpGram.domain 139 | } 140 | r.server.onConnectedHandle("tcp", target, r.tcpGram.port) 141 | } 142 | done := make(chan int) 143 | 144 | go func() { 145 | defer func() { _ = r.Close(); done <- 0 }() 146 | buf := make([]byte, 1024*8) 147 | for { 148 | _ = r.RemoteConn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(r.server.readTimeoutSecond))) 149 | if ln, err := r.RemoteConn.Read(buf); err != nil { 150 | break 151 | } else { 152 | _ = r.ClientConn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(r.server.writeTimeoutSecond))) 153 | if _, err := r.ClientConn.Write(buf[:ln]); err != nil { 154 | break 155 | } 156 | } 157 | } 158 | }() 159 | 160 | buf := make([]byte, 1024*8) 161 | for { 162 | _ = r.ClientConn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(r.server.readTimeoutSecond))) 163 | if ln, err := r.ClientConn.Read(buf); err != nil { 164 | break 165 | } else { 166 | _ = r.RemoteConn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(r.server.writeTimeoutSecond))) 167 | if _, err := r.RemoteConn.Write(buf[:ln]); err != nil { 168 | break 169 | } 170 | } 171 | } 172 | _ = r.Close() 173 | 174 | <-done 175 | } 176 | 177 | func (r *Request) transformUDP() { 178 | doneTCP := make(chan int) 179 | doneExchange := make(chan int) 180 | 181 | go func() { 182 | defer func() { _ = r.Close(); doneTCP <- 0 }() 183 | buf := make([]byte, 1) 184 | for { 185 | if _, err := r.ClientConn.Read(buf); err != nil { 186 | break 187 | } 188 | } 189 | }() 190 | 191 | //init UDPExchange 192 | if r.udpGram.UDPExchangeMap == nil { 193 | r.udpGram.UDPExchangeMap = make(map[string]*UDPExchange) 194 | } 195 | 196 | go func() { 197 | for { 198 | select { 199 | case <-time.After(time.Second * 2): 200 | r.udpGram.udpMutex.Lock() 201 | for k, v := range r.udpGram.UDPExchangeMap { 202 | if v.IsExpired() { 203 | delete(r.udpGram.UDPExchangeMap, k) 204 | } 205 | } 206 | r.udpGram.udpMutex.Unlock() 207 | case <-doneExchange: 208 | return 209 | } 210 | } 211 | 212 | }() 213 | 214 | buf := make([]byte, 65535) 215 | for { 216 | _ = r.UDPConn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(r.server.readTimeoutSecond))) 217 | ln, fromAddr, err := r.UDPConn.ReadFromUDP(buf) 218 | if err != nil { 219 | break 220 | } 221 | 222 | //get client addr and remote addr via the first package 223 | if r.udpGram.clientAddr == nil { 224 | r.udpGram.clientAddr = fromAddr 225 | } 226 | 227 | if r.udpGram.clientAddr.IP.Equal(fromAddr.IP) && r.udpGram.clientAddr.Port == fromAddr.Port { //package from client 228 | header, body, err := r.udpGram.handshake(buf[:ln]) 229 | if err != nil { 230 | break 231 | } 232 | r.udpGram.udpMutex.Lock() 233 | if exchange, ok := r.udpGram.UDPExchangeMap[r.udpGram.remoteAddr().String()]; !ok { 234 | r.udpGram.UDPExchangeMap[r.udpGram.remoteAddr().String()] = NewUDPExchange(header, 60) 235 | 236 | if r.server.onConnectedHandle != nil { 237 | var target string 238 | switch r.udpGram.atyp { 239 | case ATYPIPv4: 240 | target = r.udpGram.ip.String() 241 | case ATYPIPv6: 242 | target = r.udpGram.ip.String() 243 | case ATYPDomain: 244 | target = r.udpGram.domain 245 | } 246 | r.server.onConnectedHandle("udp", target, r.udpGram.port) 247 | } 248 | 249 | } else { 250 | exchange.Delay(60) 251 | } 252 | r.udpGram.udpMutex.Unlock() 253 | 254 | _ = r.UDPConn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(r.server.writeTimeoutSecond))) 255 | if _, er := r.UDPConn.WriteToUDP(body, r.udpGram.remoteAddr()); er != nil { 256 | break 257 | } 258 | } else { 259 | r.udpGram.udpMutex.Lock() 260 | if exchange, ok := r.udpGram.UDPExchangeMap[fromAddr.String()]; ok { //package from remote 261 | body := append(exchange.headerData, buf[:ln]...) 262 | exchange.Delay(60) 263 | _ = r.UDPConn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(r.server.writeTimeoutSecond))) 264 | if _, er := r.UDPConn.WriteToUDP(body, r.udpGram.clientAddr); er != nil { 265 | break 266 | } 267 | } 268 | r.udpGram.udpMutex.Unlock() 269 | } 270 | } 271 | close(doneExchange) 272 | _ = r.Close() 273 | 274 | <-doneTCP 275 | } 276 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "sync" 7 | ) 8 | 9 | func NewServer() *server { 10 | return &server{ 11 | readTimeoutSecond: 600, 12 | writeTimeoutSecond: 30, 13 | } 14 | } 15 | 16 | type server struct { 17 | listener *net.TCPListener 18 | mutex sync.Mutex 19 | enableUDP bool 20 | readTimeoutSecond uint //default 600 21 | writeTimeoutSecond uint //default 30 22 | headRequest *requestList 23 | 24 | authHandle AuthHandle 25 | onConnectedHandle OnConnectedHandle 26 | onStartedHandle OnStartedHandle 27 | } 28 | 29 | func (s *server) SetAuthHandle(handle AuthHandle) { 30 | s.authHandle = handle 31 | } 32 | func (s *server) EnableUDP() { 33 | s.enableUDP = true 34 | } 35 | func (s *server) SetReadTimeOutSecond(second uint) { 36 | s.readTimeoutSecond = second 37 | } 38 | func (s *server) SetWriteTimeOutSecond(second uint) { 39 | s.writeTimeoutSecond = second 40 | } 41 | func (s *server) OnStarted(h OnStartedHandle) { 42 | s.onStartedHandle = h 43 | } 44 | func (s *server) OnConnected(h OnConnectedHandle) { 45 | s.onConnectedHandle = h 46 | } 47 | func (s *server) Close() error { 48 | if s.listener == nil { 49 | return errors.New("server is not running") 50 | } 51 | if err := s.listener.Close(); err != nil { 52 | return err 53 | } else { 54 | return nil 55 | } 56 | } 57 | func (s *server) Run(addr *net.TCPAddr) error { 58 | var err error 59 | s.listener, err = net.ListenTCP("tcp", addr) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | if s.onStartedHandle != nil { 65 | s.onStartedHandle(s.listener) 66 | } 67 | for { 68 | conn, err := s.listener.AcceptTCP() 69 | if err != nil { 70 | break 71 | } 72 | go connHandle(conn, s) 73 | } 74 | 75 | s.listener = nil 76 | s.closeRequests() 77 | return nil 78 | } 79 | 80 | func (s *server) closeRequests() { 81 | for s.headRequest != nil { 82 | r := s.headRequest 83 | s.removeRequestList(r) 84 | _ = r.data.Close() 85 | } 86 | } 87 | func connHandle(conn *net.TCPConn, s *server) { 88 | r := &requestList{ 89 | prev: nil, next: nil, 90 | data: Request{ClientConn: conn, server: s, tcpGram: TCPProtocol{ 91 | authHandle: s.authHandle, 92 | }}, 93 | } 94 | s.insertRequestList(r) 95 | r.data.Process() 96 | s.removeRequestList(r) 97 | _ = r.data.Close() 98 | } 99 | 100 | func (s *server) insertRequestList(l *requestList) { 101 | s.mutex.Lock() 102 | defer s.mutex.Unlock() 103 | 104 | if s.headRequest != nil { 105 | s.headRequest.prev = l 106 | l.next = s.headRequest 107 | s.headRequest = l 108 | } else { 109 | s.headRequest = l 110 | } 111 | } 112 | func (s *server) removeRequestList(l *requestList) { 113 | s.mutex.Lock() 114 | defer s.mutex.Unlock() 115 | 116 | if s.headRequest == l { 117 | s.headRequest = l.next 118 | } 119 | if l.prev != nil { 120 | l.prev.next = l.next 121 | l.prev = nil 122 | } 123 | if l.next != nil { 124 | l.next.prev = l.prev 125 | l.next = nil 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /tcp_protocol.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "net" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | type AuthHandle func(username, password string) bool 13 | type TCPProtocol struct { 14 | cmd byte 15 | atyp byte 16 | ip net.IP //when viaUDP is false, this is remote IP otherwise UDP client IP 17 | port int //when viaUDP is false, this is remote port otherwise UDP client port 18 | domain string 19 | viaUDP bool 20 | authHandle AuthHandle 21 | } 22 | 23 | func (p *TCPProtocol) handshake(conn *net.TCPConn) error { 24 | //version 25 | data, err := p.checkVersion(conn) 26 | p.writeBuf(conn, data) 27 | if err != nil { 28 | return err 29 | } 30 | //auth 31 | data, err = p.checkAuth(conn) 32 | p.writeBuf(conn, data) 33 | if err != nil { 34 | return err 35 | } 36 | //addr 37 | atyp, cmd, addrBytes, port, data, err := p.getAddr(conn) 38 | if err != nil { 39 | p.writeBuf(conn, data) 40 | return err 41 | } else { 42 | p.cmd = cmd 43 | p.atyp = atyp 44 | } 45 | switch p.atyp { 46 | case ATYPIPv4: 47 | p.ip = net.IPv4(addrBytes[0], addrBytes[1], addrBytes[2], addrBytes[3]) 48 | case ATYPIPv6: 49 | p.ip = net.ParseIP(string(addrBytes)) 50 | case ATYPDomain: 51 | p.domain = string(addrBytes) 52 | if addr, er := net.ResolveIPAddr("ip", p.domain); er != nil { 53 | p.writeBuf(conn, []byte{Version, 0x04, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 54 | return err 55 | } else { 56 | p.ip = addr.IP 57 | } 58 | } 59 | p.port = port 60 | 61 | //check remote addr 62 | switch p.cmd { 63 | case CmdConnect: 64 | if !p.ip.IsGlobalUnicast() || p.port <= 0 { 65 | p.writeBuf(conn, []byte{Version, 0x02, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 66 | return errors.New("remote address error") 67 | } 68 | case CmdUdpAssociate: 69 | p.viaUDP = true 70 | } 71 | return nil 72 | } 73 | 74 | func (p *TCPProtocol) checkVersion(conn *net.TCPConn) ([]byte, error) { 75 | var version byte 76 | var methodLen int 77 | 78 | if buf, err := p.readBuf(conn, 2); err != nil { 79 | return []byte{Version, MethodNone}, err 80 | } else { 81 | version = buf[0] 82 | methodLen = int(buf[1]) 83 | } 84 | 85 | if version != Version || methodLen <= 0 { 86 | return []byte{Version, MethodNone}, errors.New("unsupported socks version") 87 | } 88 | 89 | if _, err := p.readBuf(conn, methodLen); err != nil { 90 | return []byte{Version, MethodNone}, err 91 | } 92 | 93 | if p.authHandle != nil { 94 | return []byte{Version, MethodAuth}, nil 95 | } else { 96 | return []byte{Version, MethodNoAuth}, nil 97 | } 98 | } 99 | func (p *TCPProtocol) checkAuth(conn *net.TCPConn) ([]byte, error) { 100 | if p.authHandle == nil { 101 | return nil, nil 102 | } 103 | 104 | var ver byte 105 | var userLen, passLen int 106 | var username, password string 107 | if buf, err := p.readBuf(conn, 2); err != nil { 108 | return []byte{0x01, 0x01}, err 109 | } else { 110 | ver = buf[0] 111 | userLen = int(buf[1]) 112 | } 113 | 114 | if ver != 0x01 || userLen <= 0 { 115 | return []byte{0x01, 0x01}, errors.New("unsupported auth version or username is empty") 116 | } 117 | 118 | if buf, err := p.readBuf(conn, userLen); err != nil { 119 | return []byte{0x01, 0x01}, err 120 | } else { 121 | username = string(buf) 122 | } 123 | 124 | if buf, err := p.readBuf(conn, 1); err != nil { 125 | return []byte{0x01, 0x01}, err 126 | } else { 127 | passLen = int(buf[0]) 128 | } 129 | 130 | if passLen <= 0 { 131 | return []byte{0x01, 0x01}, errors.New("password is empty") 132 | } 133 | 134 | if buf, err := p.readBuf(conn, passLen); err != nil { 135 | return []byte{0x01, 0x01}, err 136 | } else { 137 | password = string(buf) 138 | } 139 | 140 | if !p.authHandle(username, password) { 141 | return []byte{0x01, 0x01}, errors.New("username or password invalid") 142 | } else { 143 | return []byte{0x01, 0x00}, nil 144 | } 145 | } 146 | func (p *TCPProtocol) getAddr(conn *net.TCPConn) (atyp, cmd byte, addrBytes []byte, port int, data []byte, err error) { 147 | var ver byte 148 | if buf, er := p.readBuf(conn, 4); er != nil { 149 | err = er 150 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 151 | return 152 | } else { 153 | ver = buf[0] 154 | cmd = buf[1] 155 | atyp = buf[3] 156 | } 157 | 158 | if ver != Version { 159 | err = errors.New("unsupported socks version") 160 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 161 | return 162 | } 163 | if bytes.IndexByte([]byte{CmdConnect, CmdUdpAssociate}, cmd) == -1 { 164 | err = errors.New("unsupported CMD") 165 | data = []byte{Version, 0x07, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 166 | return 167 | } 168 | 169 | switch atyp { 170 | case ATYPIPv4: 171 | addrBytes, err = p.readBuf(conn, 4) 172 | if err != nil { 173 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 174 | return 175 | } 176 | case ATYPDomain: 177 | var domainLen int 178 | if buf, er := p.readBuf(conn, 1); er != nil { 179 | err = er 180 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 181 | return 182 | } else { 183 | domainLen = int(buf[0]) 184 | } 185 | if domainLen <= 0 { 186 | err = errors.New("length of domain is zero") 187 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 188 | return 189 | } 190 | addrBytes, err = p.readBuf(conn, domainLen) 191 | if err != nil { 192 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 193 | return 194 | } 195 | case ATYPIPv6: 196 | addrBytes, err = p.readBuf(conn, 16) 197 | if err != nil { 198 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 199 | return 200 | } 201 | default: 202 | err = errors.New("unsupported ATYP") 203 | data = []byte{Version, 0x08, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 204 | return 205 | } 206 | 207 | if buf, er := p.readBuf(conn, 2); er != nil { 208 | err = er 209 | data = []byte{Version, 0x05, 0x00, ATYPIPv4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 210 | return 211 | } else { 212 | port = int(binary.BigEndian.Uint16(buf)) 213 | } 214 | 215 | return 216 | } 217 | 218 | func (p *TCPProtocol) networkString() string { 219 | return p.ip.String() + ":" + strconv.Itoa(p.port) 220 | } 221 | 222 | func (p *TCPProtocol) readBuf(conn *net.TCPConn, ln int) ([]byte, error) { 223 | buf := make([]byte, ln) 224 | curReadLen := 0 225 | for curReadLen < ln { 226 | _ = conn.SetReadDeadline(time.Now().Add(time.Second * 10)) 227 | l, err := conn.Read(buf[curReadLen:]) 228 | if err != nil { 229 | return nil, err 230 | } 231 | curReadLen += l 232 | } 233 | return buf, nil 234 | } 235 | func (p *TCPProtocol) writeBuf(conn *net.TCPConn, data []byte) { 236 | if data != nil && len(data) > 0 { 237 | _ = conn.SetWriteDeadline(time.Now().Add(time.Second * 10)) 238 | _, _ = conn.Write(data) 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /udp_exchange.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | ) 7 | 8 | type UDPExchange struct { 9 | expiredTime time.Time 10 | headerData []byte 11 | } 12 | 13 | func NewUDPExchange(headerData []byte, lifetime uint) *UDPExchange { 14 | h := make([]byte, len(headerData)) 15 | copy(h, headerData) 16 | return &UDPExchange{ 17 | headerData: h, 18 | expiredTime: time.Now().Add(time.Second * time.Duration(lifetime)), 19 | } 20 | } 21 | 22 | func (e *UDPExchange) GetHeaderData() ([]byte, error) { 23 | if e.IsExpired() { 24 | return nil, errors.New("UDPExchange is expired") 25 | } 26 | return e.headerData, nil 27 | } 28 | func (e *UDPExchange) IsExpired() bool { 29 | return e.expiredTime.Unix() < time.Now().Unix() 30 | } 31 | func (e *UDPExchange) Delay(second uint) { 32 | e.expiredTime = time.Now().Add(time.Second * time.Duration(second)) 33 | } 34 | -------------------------------------------------------------------------------- /udp_protocol.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "net" 8 | "sync" 9 | ) 10 | 11 | type UDPProtocol struct { 12 | rsv [2]byte 13 | flag byte 14 | atyp byte 15 | ip net.IP 16 | port int 17 | 18 | domain string 19 | 20 | clientAddr *net.UDPAddr 21 | 22 | UDPExchangeMap map[string]*UDPExchange 23 | udpMutex sync.Mutex 24 | } 25 | 26 | func (p *UDPProtocol) handshake(buf []byte) ([]byte, []byte, error) { 27 | if len(buf) < 4 || !bytes.Equal(buf[:2], p.rsv[:]) || buf[2] != p.flag { 28 | return nil, nil, errors.New("fail") 29 | } 30 | 31 | var header, body []byte 32 | p.atyp = buf[3] 33 | 34 | switch p.atyp { 35 | case ATYPIPv4: 36 | if len(buf) < 10 { 37 | return nil, nil, errors.New("header is too short for IPv4") 38 | } 39 | p.ip = net.IPv4(buf[4], buf[5], buf[6], buf[7]) 40 | p.port = int(binary.BigEndian.Uint16(buf[8:10])) 41 | body = buf[10:] 42 | header = buf[:10] 43 | case ATYPDomain: 44 | if len(buf) < 5 { 45 | return nil, nil, errors.New("header is too short for domain") 46 | } 47 | domainLen := int(buf[4]) 48 | if domainLen <= 0 || len(buf) < 5+domainLen+2 { 49 | return nil, nil, errors.New("header is too short for domain") 50 | } 51 | p.domain = string(buf[5 : 5+domainLen]) 52 | if ipAddr, err := net.ResolveIPAddr("ip", p.domain); err != nil { 53 | return nil, nil, errors.New("can't resolve domain:" + p.domain) 54 | } else { 55 | p.ip = ipAddr.IP 56 | p.port = int(binary.BigEndian.Uint16(buf[5+domainLen : 5+domainLen+2])) 57 | } 58 | body = buf[5+domainLen+2:] 59 | header = buf[:5+domainLen+2] 60 | case ATYPIPv6: 61 | if len(buf) < 22 { 62 | return nil, nil, errors.New("header is too short for IPv6") 63 | } 64 | p.ip = net.ParseIP(string(buf[4:20])) 65 | p.port = int(binary.BigEndian.Uint16(buf[20:22])) 66 | body = buf[22:] 67 | header = buf[:22] 68 | default: 69 | return nil, nil, errors.New("unsupported atyp") 70 | } 71 | 72 | h := make([]byte, len(header)) 73 | copy(h, header) 74 | return h, body, nil 75 | } 76 | 77 | func (p *UDPProtocol) remoteAddr() *net.UDPAddr { 78 | return &net.UDPAddr{IP: p.ip, Port: p.port} 79 | } 80 | --------------------------------------------------------------------------------